/*
 * @(#)WorkflowProgress.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.workflow.dao;

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.FieldPosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import org.apache.commons.dbutils.DbUtils;

import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.PermissionManager;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;
import com.dcivision.framework.TextUtility;
import com.dcivision.framework.UserInfoFactory;
import com.dcivision.framework.Utility;
import com.dcivision.framework.bean.AbstractBaseObject;
import com.dcivision.framework.dao.AbstractDAObject;
import com.dcivision.framework.dao.AbstractQuery;
import com.dcivision.framework.dao.QueryUtil;
import com.dcivision.framework.dao.SubQuery;
import com.dcivision.framework.web.AbstractSearchForm;
import com.dcivision.framework.web.ListPersonalHomeForm;
import com.dcivision.user.bean.UserDelegation;
import com.dcivision.user.bean.UserGroup;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.bean.UserRole;
import com.dcivision.user.dao.MtmUserRecordUserGroupDAObject;
import com.dcivision.user.dao.MtmUserRecordUserRoleDAObject;
import com.dcivision.user.dao.UserDelegationDAObject;
import com.dcivision.user.dao.UserGroupDAObject;
import com.dcivision.user.dao.UserRecordDAObject;
import com.dcivision.user.dao.UserRoleDAObject;
import com.dcivision.workflow.bean.MtmWorkflowDynamicUserActor;
import com.dcivision.workflow.bean.MtmWorkflowProgressSystemObject;
import com.dcivision.workflow.bean.MtmWorkflowStepUserActor;
import com.dcivision.workflow.bean.WorkflowDocThroughUserRecord;
import com.dcivision.workflow.bean.WorkflowDocTrackingRecord;
import com.dcivision.workflow.bean.WorkflowProgress;
import com.dcivision.workflow.bean.WorkflowStep;
import com.dcivision.workflow.core.ProgressActionEvent;
import com.dcivision.workflow.core.SystemWorkflowConstant;
import com.dcivision.workflow.core.WorkflowProgressListener;
import com.dcivision.workflow.core.WorkflowProgressManager;
import com.dcivision.workflow.web.ListWorkflowDocThroughUserForm;
import com.dcivision.workflow.web.ListWorkflowDocTrackingForm;
import com.dcivision.workflow.web.ListWorkflowMonitoringForm;
import com.dcivision.workflow.web.ListWorkflowProgressForm;

/**
 * WorkflowProgressDAObject.java
 *
 * This class is the data access bean for table "WORKFLOW_PROGRESS".
 *
 * @author Rollo Chan
 * @company DCIVision Limited
 * @creation date 07/10/2003
 * @version $Revision: 1.249.2.15 $
 * @see com.dcivision.workflow.bean.WorkflowProgress
 */

/**
 * @author Administrator
 *
 */
public class WorkflowProgressDAObject extends AbstractDAObject {

  public static final String REVISION = "$Revision: 1.249.2.15 $";

  public static final String TABLE_NAME = "WORKFLOW_PROGRESS";

  public static final String POST_CREATE_WORKFLOW_PROGRES = "POST.CREATE.WF.PROGRESS";

  public static final String WORKFLOW_PERMISSION_TYPE_EXECUTE = "W";

  public static final String WORKFLOW_PERMISSION_TYPE_DENY_EXECUTE = "w";

  public static final String WORKFLOW_PERMISSION_TYPE_READ = "R";

  private List listenerList = new ArrayList();

  /**
   * Constructor
   *
   * @param sessionContainer The session container object
   * @param dbConn The valid database connection
   */
  public WorkflowProgressDAObject(SessionContainer sessionContainer, Connection dbConn) {
    super(sessionContainer, dbConn);
    this.addActionListener(new WorkflowProgressListener());
  }

  protected void initDBSetting() {
    this.baseTableName = TABLE_NAME;
    this.vecDBColumn.add("ID");
    this.vecDBColumn.add("WORKFLOW_STEP_ID");
    this.vecDBColumn.add("TRACK_ID");
    this.vecDBColumn.add("CANCEL_FLAG");
    this.vecDBColumn.add("COMPLETE_FLAG");
    this.vecDBColumn.add("SEQ_NO");
    this.vecDBColumn.add("STATUS");
    this.vecDBColumn.add("POST_PROGRESS");
    this.vecDBColumn.add("DUE_DATE");
    this.vecDBColumn.add("NEXT_STEP_DUE_DATES");
    this.vecDBColumn.add("PROGRESS_PRIORITY");
    this.vecDBColumn.add("USER_DEF_1");
    this.vecDBColumn.add("USER_DEF_2");
    this.vecDBColumn.add("USER_DEF_3");
    this.vecDBColumn.add("USER_DEF_4");
    this.vecDBColumn.add("USER_DEF_5");
    this.vecDBColumn.add("RECORD_STATUS");
    this.vecDBColumn.add("UPDATE_COUNT");
    this.vecDBColumn.add("CREATOR_ID");
    this.vecDBColumn.add("CREATE_DATE");
    this.vecDBColumn.add("UPDATER_ID");
    this.vecDBColumn.add("UPDATE_DATE");
  }

  protected synchronized AbstractBaseObject getByID(Integer id) throws ApplicationException {

    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, ");
        sqlStat.append("       WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ALLOW_ASSIGN_DUE_DATE, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ALLOW_STOP, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP WS, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC ");
        sqlStat.append("WHERE  A.ID = ? AND ");
        sqlStat.append("       A.WORKFLOW_STEP_ID = WS.ID AND ");
        sqlStat.append("       WS.WORKFLOW_RECORD_ID = WR.ID AND "); 
        sqlStat.append("       WR.WORKFLOW_CATEGORY_ID = SOWC.ID ");
        sqlStat.append("       AND A.RECORD_STATUS = ? ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, id);
        this.setPrepareStatement(preStat, 2, GlobalConstant.RECORD_STATUS_ACTIVE);
        rs = preStat.executeQuery();
        if (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setAllowAssignDueDate(getResultSetString(rs, "ALLOW_ASSIGN_DUE_DATE"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setAllowStop(getResultSetString(rs, "ALLOW_STOP"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));

          WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionContainer, dbConn);
          tmpWorkflowProgress.setWorkflowStepSource((WorkflowStep) stepDAO.getObjectByID(tmpWorkflowProgress.getWorkflowStepID()));

          return (tmpWorkflowProgress);
        } else {
          throw new ApplicationException(ErrorConstant.DB_RECORD_NOT_FOUND_ERROR);
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  
  }
  protected synchronized List getList(AbstractSearchForm searchForm) throws ApplicationException {
    PreparedStatement preStat = null;
    PreparedStatement preStatCnt = null;
    ResultSet rs = null;
    ResultSet rsCnt = null;
    StringBuffer sqlStat = new StringBuffer();
    StringBuffer sqlStatCnt = new StringBuffer();
    List result = new ArrayList();
    int totalNumOfRecord = 0;
    int rowLoopCnt = 0;
    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, ");
        sqlStat.append("       WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP WS, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? AND ");
        sqlStat.append("       A.WORKFLOW_STEP_ID = WS.ID AND ");
        sqlStat.append("       WS.WORKFLOW_RECORD_ID = WR.ID AND ");
        sqlStat.append("       WR.WORKFLOW_CATEGORY_ID = SOWC.ID ");

        // Form the WHERE clause for filtering.
        if (searchForm.isSearchable()) {
          String searchField = getSearchColumn(searchForm.getBasicSearchField());
          sqlStat.append("AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? ");
        }

        // format the sql for any 'LIKE' statement contained
        sqlStat = this.getFormattedSQL(sqlStat.toString());

        // Form the ORDER clause for sorting.
        if (searchForm.isSortable()) {
          String sortAttribute = searchForm.getSortAttribute();
          if (sortAttribute.indexOf(".") < 0) {
            sortAttribute = "A." + sortAttribute;
          }
          sqlStat.append("ORDER BY " + sortAttribute + " " + searchForm.getSortOrder());
        }

        // Get total number of record return.
        sqlStatCnt = this.getSelectCountSQL(sqlStat);
        preStatCnt = dbConn.prepareStatement(sqlStatCnt.toString());
        this.setPrepareStatement(preStatCnt, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        if (searchForm.isSearchable()) {
          String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
          this.setPrepareStatement(preStatCnt, 2, searchKeyword);
        }
        rsCnt = preStatCnt.executeQuery();
        if (rsCnt.next()) {
          totalNumOfRecord = rsCnt.getInt(1);
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }

        // Retrieve the result in row basis.
        sqlStat = this.getSelectListSQL(sqlStat, startOffset, pageSize);
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        if (searchForm.isSearchable()) {
          String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
          this.setPrepareStatement(preStat, 2, searchKeyword);
        }
        rs = preStat.executeQuery();

        this.positionCursor(rs, startOffset, pageSize);

        while (rs.next() && rowLoopCnt < pageSize) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));
          tmpWorkflowProgress.setRecordCount(totalNumOfRecord);
          tmpWorkflowProgress.setRowNum(startOffset++);
          ++rowLoopCnt;
          result.add(tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }
      }
    }
  }

  protected synchronized List getList() throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List result = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, ");
        sqlStat.append("       WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP WS, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? AND ");
        sqlStat.append("       A.WORKFLOW_STEP_ID = WS.ID AND ");
        sqlStat.append("       WS.WORKFLOW_RECORD_ID = WR.ID AND ");
        sqlStat.append("       WR.WORKFLOW_CATEGORY_ID = SOWC.ID ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        rs = preStat.executeQuery();
        while (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));
          result.add(tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  protected void validateInsert(AbstractBaseObject obj) throws ApplicationException {
  }

  protected void validateUpdate(AbstractBaseObject obj) throws ApplicationException {
  }

  protected void validateDelete(AbstractBaseObject obj) throws ApplicationException {
  }

  protected synchronized AbstractBaseObject insert(AbstractBaseObject obj) throws ApplicationException {
    PreparedStatement preStat = null;
    StringBuffer sqlStat = new StringBuffer();
    WorkflowProgress tmpWorkflowProgress = (WorkflowProgress) ((WorkflowProgress) obj).clone();

    synchronized (dbConn) {
      try {
        Integer nextID = getNextPrimaryID();
        Timestamp currTime = Utility.getCurrentTimestamp();
        sqlStat.append("INSERT ");
        sqlStat.append("INTO   WORKFLOW_PROGRESS(ID, WORKFLOW_STEP_ID, TRACK_ID, CANCEL_FLAG, COMPLETE_FLAG, SEQ_NO, STATUS, POST_PROGRESS, DUE_DATE, NEXT_STEP_DUE_DATES, PROGRESS_PRIORITY, USER_DEF_1, USER_DEF_2, USER_DEF_3, USER_DEF_4, USER_DEF_5, RECORD_STATUS, UPDATE_COUNT, CREATOR_ID, CREATE_DATE, UPDATER_ID, UPDATE_DATE) ");
        sqlStat.append("VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        setPrepareStatement(preStat, 1, nextID);
        setPrepareStatement(preStat, 2, tmpWorkflowProgress.getWorkflowStepID());
        setPrepareStatement(preStat, 3, tmpWorkflowProgress.getTrackID());
        setPrepareStatement(preStat, 4, tmpWorkflowProgress.getCancelFlag());
        setPrepareStatement(preStat, 5, tmpWorkflowProgress.getCompleteFlag());
        setPrepareStatement(preStat, 6, tmpWorkflowProgress.getSeqNo());
        setPrepareStatement(preStat, 7, tmpWorkflowProgress.getStatus());
        setPrepareStatement(preStat, 8, tmpWorkflowProgress.getPostProgress());
        setPrepareStatement(preStat, 9, tmpWorkflowProgress.getDueDate());
        setPrepareStatement(preStat, 10, tmpWorkflowProgress.getNextStepDueDates());
        setPrepareStatement(preStat, 11, tmpWorkflowProgress.getProgressPriority());
        setPrepareStatement(preStat, 12, tmpWorkflowProgress.getUserDef1());
        setPrepareStatement(preStat, 13, tmpWorkflowProgress.getUserDef2());
        setPrepareStatement(preStat, 14, tmpWorkflowProgress.getUserDef3());
        setPrepareStatement(preStat, 15, tmpWorkflowProgress.getUserDef4());
        setPrepareStatement(preStat, 16, tmpWorkflowProgress.getUserDef5());
        setPrepareStatement(preStat, 17, GlobalConstant.RECORD_STATUS_ACTIVE);
        setPrepareStatement(preStat, 18, new Integer(0));
        setPrepareStatement(preStat, 19, sessionContainer.getUserRecordID());
        setPrepareStatement(preStat, 20, currTime);
        setPrepareStatement(preStat, 21, sessionContainer.getUserRecordID());
        setPrepareStatement(preStat, 22, currTime);
        preStat.executeUpdate();
        tmpWorkflowProgress.setID(nextID);
        tmpWorkflowProgress.setCreatorID(sessionContainer.getUserRecordID());
        tmpWorkflowProgress.setCreateDate(currTime);
        tmpWorkflowProgress.setUpdaterID(sessionContainer.getUserRecordID());
        tmpWorkflowProgress.setUpdateDate(currTime);
        tmpWorkflowProgress.setUpdateCount(new Integer(0));
        tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
        tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));

        log.info("*** about to START notify listener for POST_CREATE_WORKFLOW_PROGRESS");
        WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionContainer, dbConn);

        tmpWorkflowProgress.setWorkflowStepSource((WorkflowStep) stepDAO.getObjectByID(tmpWorkflowProgress.getWorkflowStepID()));

        this.notifyActionListener(WorkflowProgressDAObject.POST_CREATE_WORKFLOW_PROGRES, new Object[] { tmpWorkflowProgress });
        log.info("*** about to STOP notify listener for POST_CREATE_WORKFLOW_PROGRESS");

        return (tmpWorkflowProgress);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_INSERT_ERROR, e);
      } finally {
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  protected synchronized AbstractBaseObject update(AbstractBaseObject obj) throws ApplicationException {
    PreparedStatement preStat = null;
    StringBuffer sqlStat = new StringBuffer();
    WorkflowProgress tmpWorkflowProgress = (WorkflowProgress) ((WorkflowProgress) obj).clone();

    synchronized (dbConn) {
      try {
        int updateCnt = 0;
        Timestamp currTime = Utility.getCurrentTimestamp();
        sqlStat.append("UPDATE WORKFLOW_PROGRESS ");
        sqlStat.append("SET  WORKFLOW_STEP_ID=?, TRACK_ID=?, CANCEL_FLAG=?, COMPLETE_FLAG=?, SEQ_NO=?, STATUS=?, POST_PROGRESS=?, DUE_DATE=?, NEXT_STEP_DUE_DATES=?, PROGRESS_PRIORITY=?, USER_DEF_1=?, USER_DEF_2=?, USER_DEF_3=?, USER_DEF_4=?, USER_DEF_5=?, UPDATE_COUNT=?, UPDATER_ID=?, UPDATE_DATE=? ");
        sqlStat.append("WHERE  ID=? AND UPDATE_COUNT=? ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        setPrepareStatement(preStat, 1, tmpWorkflowProgress.getWorkflowStepID());
        setPrepareStatement(preStat, 2, tmpWorkflowProgress.getTrackID());
        setPrepareStatement(preStat, 3, tmpWorkflowProgress.getCancelFlag());
        setPrepareStatement(preStat, 4, tmpWorkflowProgress.getCompleteFlag());
        setPrepareStatement(preStat, 5, tmpWorkflowProgress.getSeqNo());
        setPrepareStatement(preStat, 6, tmpWorkflowProgress.getStatus());
        setPrepareStatement(preStat, 7, tmpWorkflowProgress.getPostProgress());
        setPrepareStatement(preStat, 8, tmpWorkflowProgress.getDueDate());
        setPrepareStatement(preStat, 9, tmpWorkflowProgress.getNextStepDueDates());
        setPrepareStatement(preStat, 10, tmpWorkflowProgress.getProgressPriority());
        setPrepareStatement(preStat, 11, tmpWorkflowProgress.getUserDef1());
        setPrepareStatement(preStat, 12, tmpWorkflowProgress.getUserDef2());
        setPrepareStatement(preStat, 13, tmpWorkflowProgress.getUserDef3());
        setPrepareStatement(preStat, 14, tmpWorkflowProgress.getUserDef4());
        setPrepareStatement(preStat, 15, tmpWorkflowProgress.getUserDef5());
        setPrepareStatement(preStat, 16, new Integer(tmpWorkflowProgress.getUpdateCount().intValue() + 1));
        //if (tmpWorkflowProgress.getUpdaterID()!=null && tmpWorkflowProgress.getUpdaterID().intValue()>0){//simon_del
          //setPrepareStatement(preStat, 17, tmpWorkflowProgress.getUpdaterID() );//simon_del
        //}else{//simon_del
          setPrepareStatement(preStat, 17, sessionContainer.getUserRecordID());//simon_add
        //}//simon_del
        setPrepareStatement(preStat, 18, currTime);
        setPrepareStatement(preStat, 19, tmpWorkflowProgress.getID());
        setPrepareStatement(preStat, 20, tmpWorkflowProgress.getUpdateCount());

        updateCnt = preStat.executeUpdate();
        if (updateCnt == 0) {
          throw new ApplicationException(ErrorConstant.DB_CONCURRENT_ERROR);
        } else {
          tmpWorkflowProgress.setUpdaterID(sessionContainer.getUserRecordID());
          tmpWorkflowProgress.setUpdateDate(currTime);
          tmpWorkflowProgress.setUpdateCount(new Integer(tmpWorkflowProgress.getUpdateCount().intValue() + 1));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(sessionContainer.getUserRecordID()));//simon_add
          //tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));//simon_del
          return (tmpWorkflowProgress);
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_UPDATE_ERROR, e);
      } finally {
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  protected synchronized AbstractBaseObject delete(AbstractBaseObject obj) throws ApplicationException {
    PreparedStatement preStat = null;
    StringBuffer sqlStat = new StringBuffer();
    WorkflowProgress tmpWorkflowProgress = (WorkflowProgress) ((WorkflowProgress) obj).clone();

    synchronized (dbConn) {
      try {
        int updateCnt = 0;
        sqlStat.append("DELETE ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS ");
        sqlStat.append("WHERE  ID=? AND UPDATE_COUNT=? ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        setPrepareStatement(preStat, 1, tmpWorkflowProgress.getID());
        setPrepareStatement(preStat, 2, tmpWorkflowProgress.getUpdateCount());
        updateCnt = preStat.executeUpdate();
        if (updateCnt == 0) {
          throw new ApplicationException(ErrorConstant.DB_CONCURRENT_ERROR);
        } else {
          return (tmpWorkflowProgress);
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_DELETE_ERROR, e);
      } finally {
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  protected synchronized void auditTrail(String opMode, AbstractBaseObject obj) throws ApplicationException {
    Vector oldValues = new Vector();
    Vector newValues = new Vector();
    WorkflowProgress tmpWorkflowProgress = (WorkflowProgress) this.oldValue;

    if (tmpWorkflowProgress != null) {
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getID()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getWorkflowStepID()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getTrackID()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getCancelFlag()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getCompleteFlag()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getSeqNo()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getStatus()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getPostProgress()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getDueDate()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getNextStepDueDates()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getProgressPriority()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getUserDef1()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getUserDef2()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getUserDef3()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getUserDef4()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getUserDef5()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getRecordStatus()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getUpdateCount()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getCreatorID()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getCreateDate()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getUpdaterID()));
      oldValues.add(toAuditTrailValue(tmpWorkflowProgress.getUpdateDate()));
    }

    tmpWorkflowProgress = (WorkflowProgress) obj;
    if (tmpWorkflowProgress != null) {
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getID()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getWorkflowStepID()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getTrackID()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getCancelFlag()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getCompleteFlag()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getSeqNo()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getStatus()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getPostProgress()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getDueDate()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getNextStepDueDates()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getProgressPriority()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getUserDef1()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getUserDef2()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getUserDef3()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getUserDef4()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getUserDef5()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getRecordStatus()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getUpdateCount()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getCreatorID()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getCreateDate()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getUpdaterID()));
      newValues.add(toAuditTrailValue(tmpWorkflowProgress.getUpdateDate()));
    }

    auditTrailBase(opMode, oldValues, newValues);
  }

  /*************************************************************************************************************************************************************
   * DON'T Modify the codes above unless you know what you are doing!!! * Put your own functions beblow. * For FINDER methods, the function name should be in
   * the notation: * public Object getObjectBy<Criteria>() * - e.g. public Object getObjectByCode() * public List getListBy<Criteria>() * - e.g. public List
   * getListByUserID() * For OPERATION methods, the function name should be in the notation: * public void <Operation>ObjectBy<Criteria>() * - e.g. public void
   * deleteObjectByCode() * public void <Operation>ListBy<Criteria>() * - e.g. public void deleteListByUserID() *
   ************************************************************************************************************************************************************/

  /**
   * Gets a list of workflow progress of a specific track
   *
   * @param trackID The workflow track ID
   * @return List of workflow progress of this track ID
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized List getListByTrackID(Integer trackID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List result = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, ");
        sqlStat.append("       WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP WS, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? AND A.TRACK_ID = ? AND ");
        sqlStat.append("       A.WORKFLOW_STEP_ID = WS.ID AND ");
        sqlStat.append("       WS.WORKFLOW_RECORD_ID = WR.ID AND ");
        sqlStat.append("       WR.WORKFLOW_CATEGORY_ID = SOWC.ID ");
        sqlStat.append("ORDER BY A.SEQ_NO ASC ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, 2, trackID);
        rs = preStat.executeQuery();
        while (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));
          result.add(tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Gets a list of workflow progress of a specific track and filter by the given status
   *
   * @param trackID The workflow track ID
   * @param status The progress status that want to filter by
   * @return List of desired workflow progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized List getListByTrackIDAndStatus(Integer trackID, String status) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List result = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, ");
        sqlStat.append("       WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP WS, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? AND A.TRACK_ID = ? AND A.STATUS = ? AND ");
        sqlStat.append("       A.WORKFLOW_STEP_ID = WS.ID AND ");
        sqlStat.append("       WS.WORKFLOW_RECORD_ID = WR.ID AND ");
        sqlStat.append("       WR.WORKFLOW_CATEGORY_ID = SOWC.ID ");
        sqlStat.append("ORDER BY A.SEQ_NO ASC ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, 2, trackID);
        this.setPrepareStatement(preStat, 3, status);
        rs = preStat.executeQuery();
        while (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));
          result.add(tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Gets a list of finished workflow progress of a specific track
   *
   * @param trackID The workflow track ID
   * @return List of workflow progress of this track ID
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  // TODO: change to use getProgressListByTrackIDAndStatus(trackID, new
  // String[]{...});
  public synchronized List getFinishedProgressListByTrackID(Integer trackID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List result = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, ");
        sqlStat.append("       WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP WS, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? AND A.TRACK_ID = ? AND A.STATUS <> ? AND ");
        sqlStat.append("       A.STATUS <> ? AND A.STATUS <> ? AND ");
        sqlStat.append("       A.WORKFLOW_STEP_ID = WS.ID AND ");
        sqlStat.append("       WS.WORKFLOW_RECORD_ID = WR.ID AND ");
        sqlStat.append("       WR.WORKFLOW_CATEGORY_ID = SOWC.ID ");
        sqlStat.append("ORDER BY A.SEQ_NO ASC ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, 2, trackID);
        this.setPrepareStatement(preStat, 3, WorkflowProgress.STATUS_PENDING);
        this.setPrepareStatement(preStat, 4, WorkflowProgress.STATUS_IN_PROGRESS);
        this.setPrepareStatement(preStat, 5, WorkflowProgress.STATUS_LOCK);
        rs = preStat.executeQuery();
        while (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));
          result.add(tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Gets all the non-finished progress of the given track
   *
   * @param trackID The workflow track ID
   * @return List of desired progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized List getNonFinishedProgressListByTrackID(Integer trackID) throws ApplicationException {
    return getProgressListByTrackIDAndStatus(trackID, new String[] { WorkflowProgress.STATUS_PENDING, WorkflowProgress.STATUS_IN_PROGRESS });
  }

  /**
   * Gets all the pending (exclude in progress) progress of the given track
   *
   * @param trackID The workflow track ID
   * @return List of desired progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized List getPendingProgressListByTrackID(Integer trackID) throws ApplicationException {
    // return getProgressListByTrackIDAndStatus ( trackID, new
    // String[]{WorkflowProgress.STATUS_PENDING} );
    return getNonFinishedProgressListByTrackID(trackID);
  }

  /**
   * Gets all the progress of the given track and filter by the given status
   *
   * @param trackID The workflow track ID
   * @param status Array of status that to be filtered
   * @return List of desired progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized List getProgressListByTrackIDAndStatus(Integer trackID, String status[]) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List result = new ArrayList();

    synchronized (dbConn) {
      try {
        WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionContainer, dbConn);

        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, \n");
        sqlStat.append("  WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR \n");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP WS, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC ");
        sqlStat.append("WHERE A.WORKFLOW_STEP_ID = WS.ID \n");
        sqlStat.append("  AND WS.WORKFLOW_RECORD_ID = WR.ID \n");
        sqlStat.append("  AND WR.WORKFLOW_CATEGORY_ID = SOWC.ID \n");
        sqlStat.append("  AND A.RECORD_STATUS = ? \n");
        sqlStat.append("  AND A.TRACK_ID = ? \n");
        if (status != null && status.length > 0) {
          sqlStat.append("  AND (");
          for (int i = 0; i < status.length; i++) {
            sqlStat.append("           ").append((i > 0) ? " OR " : "").append("  A.STATUS = ? \n");
          }
          sqlStat.append("            )\n");
        }
        sqlStat.append("ORDER BY A.SEQ_NO ASC ");

        log.debug(sqlStat);
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, 2, trackID);
        // this.setPrepareStatement(preStat, 3, WorkflowProgress.STATUS_PENDING);
        if (status != null && status.length > 0) {
          for (int i = 0; i < status.length; i++) {
            this.setPrepareStatement(preStat, i + 3, status[i]);
          }
        }
        rs = preStat.executeQuery();
        while (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));
          tmpWorkflowProgress.setWorkflowStepSource((WorkflowStep) stepDAO.getObjectByID(tmpWorkflowProgress.getWorkflowStepID()));

          result.add(tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Gets a list of workflow progress by the given trackID, stepID List, and status
   *
   * @param trackID The workflow track ID
   * @param stepIDList List of step ID that should be included
   * @param status Select only this status
   * @return List of desired progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized List getListByTrackIDStepIDListAndStatus(Integer trackID, List stepIDList, String status) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List result = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? AND A.STATUS = ? AND A.TRACK_ID = ? AND (");
        for (int i = 0; i < stepIDList.size(); i++) {
          if (i > 0) {
            sqlStat.append(" OR ");
          }
          sqlStat.append("A.WORKFLOW_STEP_ID = ?");
        }
        sqlStat.append(")");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, 2, status);
        this.setPrepareStatement(preStat, 3, trackID);
        for (int i = 0; i < stepIDList.size(); i++) {
          this.setPrepareStatement(preStat, i + 4, (Integer) stepIDList.get(i));
        }
        rs = preStat.executeQuery();
        while (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          result.add(tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }
/**
 * 
 * @param trackID
 * @param stepID
 * @return
 * @throws ApplicationException
 */
public WorkflowProgress getObjectByTrackIDStepIDStatus(Integer trackID,Integer stepID)throws ApplicationException {

  WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
  PreparedStatement preStat = null;
  ResultSet rs = null;
  StringBuffer sqlStat = new StringBuffer();

  synchronized (dbConn) {
    try {
      sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE ");
      sqlStat.append("FROM   WORKFLOW_PROGRESS A ");
      sqlStat.append("WHERE  A.RECORD_STATUS = ? AND A.TRACK_ID = ?  AND A.WORKFLOW_STEP_ID = ? AND (");
      sqlStat.append("  A.STATUS = ? ");
      sqlStat.append(" OR A.STATUS = ? ");
      sqlStat.append(" OR A.STATUS = ? ");
      sqlStat.append(")");
      preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
      this.setPrepareStatement(preStat, 2, trackID);
        this.setPrepareStatement(preStat,  3, stepID);
        this.setPrepareStatement(preStat, 4, WorkflowProgress.STATUS_LOCK);
        this.setPrepareStatement(preStat, 5, WorkflowProgress.STATUS_IN_PROGRESS);
        this.setPrepareStatement(preStat, 6, WorkflowProgress.STATUS_PENDING);
      rs = preStat.executeQuery();
      if (rs.next()) {
        tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
        tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
        tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
        tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
        tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
        tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
        tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
        tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
        tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
        tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
        tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
        tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
        tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
        tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
        tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
        tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
        tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
        tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
        tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
        tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
        tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
        tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
        tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
        tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
       
      }
      return (tmpWorkflowProgress);
    } catch (ApplicationException appEx) {
      throw appEx;
    } catch (SQLException sqle) {
      log.error(sqle, sqle);
      throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
    } catch (Exception e) {
      log.error(e, e);
      throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
    } finally {
      try {
        rs.close();
      } catch (Exception ignore) {
      } finally {
        rs = null;
      }
      try {
        preStat.close();
      } catch (Exception ignore) {
      } finally {
        preStat = null;
      }
    }
  }

  
}
  /**
   * Gets a list of workflow progress by the given trackID and stepID List
   *
   * @param trackID The workflow track ID
   * @param stepIDList List of step ID that should be included
   * @return List of desired progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized List getListByTrackIDStepIDList(Integer trackID, List stepIDList) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List result = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? AND (A.STATUS = '" + WorkflowProgress.STATUS_PENDING + "' OR A.STATUS = '" + WorkflowProgress.STATUS_IN_PROGRESS + "' OR A.STATUS = '"
          + WorkflowProgress.STATUS_POST_PROGRESS + "') AND A.TRACK_ID = ? AND (");
        for (int i = 0; i < stepIDList.size(); i++) {
          if (i > 0) {
            sqlStat.append(" OR ");
          }
          sqlStat.append("A.WORKFLOW_STEP_ID = ?");
        }
        sqlStat.append(")");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, 2, trackID);
        for (int i = 0; i < stepIDList.size(); i++) {
          this.setPrepareStatement(preStat, i + 3, (Integer) stepIDList.get(i));
        }
        rs = preStat.executeQuery();
        while (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          result.add(tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Gets a lock list of workflow progress by the given trackID and stepID List
   *
   * @param trackID The workflow track ID
   * @param stepIDList List of step ID that should be included
   * @param status Select only this status
   * @return List of desired progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized List getLockedListByTrackIDStepIDList(Integer trackID, List stepIDList) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List result = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? AND A.STATUS = '" + WorkflowProgress.STATUS_LOCK + "' AND A.TRACK_ID = ? AND (");
        for (int i = 0; i < stepIDList.size(); i++) {
          if (i > 0) {
            sqlStat.append(" OR ");
          }
          sqlStat.append("A.WORKFLOW_STEP_ID = ?");
        }
        sqlStat.append(")");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, 2, trackID);
        for (int i = 0; i < stepIDList.size(); i++) {
          this.setPrepareStatement(preStat, i + 3, (Integer) stepIDList.get(i));
        }
        rs = preStat.executeQuery();
        while (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          result.add(tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Gets a list of workflow progress by the given stepID and trackID
   *
   * @param stepID The workflow step id
   * @param trackID The workflow track id
   * @return List of defired workflow progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized List getListByStepIDAndTrackID(Integer stepID, Integer trackID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List result = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, ");
        sqlStat.append("       WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP WS, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? AND ");
        sqlStat.append("       A.WORKFLOW_STEP_ID = WS.ID AND ");
        sqlStat.append("       WS.WORKFLOW_RECORD_ID = WR.ID AND ");
        sqlStat.append("       WR.WORKFLOW_CATEGORY_ID = SOWC.ID AND ");
        sqlStat.append("       A.WORKFLOW_STEP_ID = ? AND A.TRACK_ID = ? ");
        sqlStat.append("ORDER BY A.SEQ_NO ASC ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, 2, stepID);
        this.setPrepareStatement(preStat, 3, trackID);
        rs = preStat.executeQuery();
        while (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));

          result.add(tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  public synchronized List getCompleteListByStepIDAndTrackID(Integer stepID, Integer trackID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List result = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, ");
        sqlStat.append("       WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP WS, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? AND ");
        sqlStat.append("       A.WORKFLOW_STEP_ID = WS.ID AND ");
        sqlStat.append("       WS.WORKFLOW_RECORD_ID = WR.ID AND ");
        sqlStat.append("       WR.WORKFLOW_CATEGORY_ID = SOWC.ID AND ");
        sqlStat.append("       A.WORKFLOW_STEP_ID = ? AND A.TRACK_ID = ? AND ");
        sqlStat.append("       A.STATUS<> ? AND A.STATUS<> ? AND A.STATUS<> ? ");
        sqlStat.append("ORDER BY A.SEQ_NO ASC ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, 2, stepID);
        this.setPrepareStatement(preStat, 3, trackID);
        this.setPrepareStatement(preStat, 4, WorkflowProgress.STATUS_PENDING);
        this.setPrepareStatement(preStat, 5, WorkflowProgress.STATUS_IN_PROGRESS);
        this.setPrepareStatement(preStat, 6, WorkflowProgress.STATUS_LOCK);
        rs = preStat.executeQuery();
        while (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));

          result.add(tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Gets a list of progress for generating document tracking report by document reference number (included in the searchForm object)
   *
   * @param searchForm The ListWorkflowDocTrackingForm object that contains the document reference number
   * @return List of desired workflow progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.web.ListWorkflowDocTrackingForm
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized List getListDocTracking(AbstractSearchForm searchForm) throws ApplicationException {
    MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);
    PreparedStatement preStat = null;
    PreparedStatement preStatCnt = null;
    ResultSet rs = null;
    ResultSet rsCnt = null;
    StringBuffer sqlStat = new StringBuffer();
    StringBuffer sqlStatCnt = new StringBuffer();
    List result = new ArrayList();
    int totalNumOfRecord = 0;
    int rowLoopCnt = 0;
    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());
    String docReferenceNumber = "";
    String trackID = null;
    String trackIDs = "-1";

    // get the track ID list by document reference number
    docReferenceNumber = ((ListWorkflowDocTrackingForm) searchForm).getDocReferenceNumber();
    trackID = ((ListWorkflowDocTrackingForm) searchForm).getTrackID();
    if (Utility.isEmpty(docReferenceNumber) && Utility.isEmpty(trackID)) {
      // If docReferenceNumber is not passed, don't do the search
      return new ArrayList();
    }

    if (!Utility.isEmpty(docReferenceNumber)) {
      List tmpWfProgressIDList = this.getTrackIDListByDocumentReferenceNumber(((ListWorkflowDocTrackingForm) searchForm).getDocReferenceNumber());
      for (int k = 0; k < tmpWfProgressIDList.size(); k++) {
        trackIDs += "," + (tmpWfProgressIDList.get(k).toString());
      }
    } else if (!Utility.isEmpty(trackID)) {
      trackIDs = trackID;
    }

    synchronized (dbConn) {
      try {
        StringBuffer trackIDString = new StringBuffer("0");
        sqlStat.append("SELECT DISTINCT A.TRACK_ID\n");
        sqlStat.append("FROM    WORKFLOW_PROGRESS A, WORKFLOW_STEP B, WORKFLOW_RECORD C, MTM_WF_STEP_USER_ACTOR D, MTM_WF_PROGRESS_USER_RECORD E \n");
        sqlStat.append("WHERE   E.WORKFLOW_PROGRESS_ID = A.ID AND \n");
        sqlStat.append("        A.WORKFLOW_STEP_ID = B.ID AND \n");
        sqlStat.append("        D.ACTION_TYPE = ? AND \n");
        sqlStat.append("        B.ACTION_TYPE = ? AND \n");
        sqlStat.append("        C.ID = B.WORKFLOW_RECORD_ID AND \n");
        sqlStat.append("        C.RECORD_STATUS = ? AND \n");
        sqlStat.append("        B.ID = D.WORKFLOW_STEP_ID AND \n");
        sqlStat.append("        " + getInSQL("A.TRACK_ID", trackIDs) + " \n");
        sqlStat.append("    ORDER BY A.TRACK_ID ASC\n");

        preStat = dbConn.prepareStatement(sqlStat.toString());
        this.setPrepareStatement(preStat, 1, MtmWorkflowStepUserActor.ACTION_TYPE_EXECUTION);
        this.setPrepareStatement(preStat, 2, WorkflowStep.ACTION_TYPE_SUBMIT);
        this.setPrepareStatement(preStat, 3, GlobalConstant.RECORD_STATUS_ACTIVE);
        rs = preStat.executeQuery();

        // Should do the paging here because each track id may represent 1
        // record in the tracking report
        // * skip the first n record until reach the starting record of the page
        String sTrackID = "";
        for (int i = 0; i < startOffset - 1 && rs.next();) {
          if (sTrackID.equals(getResultSetString(rs, "TRACK_ID"))) {
            continue;
          }
          sTrackID = getResultSetString(rs, "TRACK_ID");
          i++;
        }
        while (rs.next() && rowLoopCnt < pageSize) {
          if (trackIDString.length() > 0) {
            trackIDString.append(",");
          }
          trackIDString.append(getResultSetString(rs, "TRACK_ID"));
          ++rowLoopCnt;
        }
        rs.close();
        preStat.close();

        // Get the total number of records in this report
        StringBuffer sqlTmp = this.getSelectCountSQL(sqlStat);
        sqlStatCnt = new StringBuffer("SELECT COUNT(DISTINCT A.TRACK_ID) FROM ");
        int idx = sqlTmp.indexOf("FROM ");
        sqlStatCnt.append(sqlTmp.substring(idx + 5));
        preStatCnt = dbConn.prepareStatement(sqlStatCnt.toString());
        this.setPrepareStatement(preStatCnt, 1, MtmWorkflowStepUserActor.ACTION_TYPE_EXECUTION);
        this.setPrepareStatement(preStatCnt, 2, WorkflowStep.ACTION_TYPE_SUBMIT);
        this.setPrepareStatement(preStatCnt, 3, GlobalConstant.RECORD_STATUS_ACTIVE);
        rsCnt = preStatCnt.executeQuery();
        if (rsCnt.next()) {
          totalNumOfRecord = rsCnt.getInt(1);
        }
        log.debug("total number of records in the report = " + totalNumOfRecord);
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }
        // Finished getting the total number of record in this report

        // Now select ALL the workflow progresses that is within the above
        // selected track id
        // Note that if this page of report contains 10 records, it may contains
        // total of more than 10 workflow progresses
        sqlStat = new StringBuffer();
        sqlStat.append("SELECT  A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.COMPLETE_FLAG, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, B.WORKFLOW_CODE, B.WORKFLOW_VERSION, B.START_DATE, B.END_DATE, B.DESCRIPTION AS WORKFLOW_DESCRIPTION, C.WORKFLOW_CATEGORY_NAME, B.WORKFLOW_CATEGORY_ID, B.ID AS WORKFLOW_RECORD_ID, D.STEP_SEQ, D.STEP_NAME, D.ACTION_TYPE, D.DESCRIPTION AS STEP_DESCRIPTION, D.PRIORITY, D.ON_NO_RESPONSE_AFTER, D.ON_NO_RESPONSE_FOR \n");
        sqlStat.append("FROM    WORKFLOW_STEP D, WORKFLOW_RECORD B, SETUP_OPTION_WORKFLOW_CATEGORY C, WORKFLOW_PROGRESS A \n");
        sqlStat.append("WHERE   A.WORKFLOW_STEP_ID = D.ID AND \n");
        sqlStat.append("        D.WORKFLOW_RECORD_ID = B.ID AND \n");
        sqlStat.append("        B.WORKFLOW_CATEGORY_ID = C.ID AND \n");
        sqlStat.append("        B.RECORD_STATUS = ? AND \n");
        sqlStat.append("        D.STEP_SEQ <> ? AND \n");
        sqlStat.append("        " + getInSQL("A.TRACK_ID", trackIDString.toString()) + " \n");
        sqlStat.append("ORDER BY A.TRACK_ID, A.SEQ_NO ASC, A.CREATE_DATE ASC");

        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, 2, WorkflowStep.END_STEP_SEQ_NO);
        rs = preStat.executeQuery();

        WorkflowDocTrackingRecord workflowDocTrackingRecord = null;
        String currentTrackID = null;
        while (rs.next()) {
          String tmpTrackID = getResultSetString(rs, "TRACK_ID");
          if (!tmpTrackID.equals(currentTrackID)) {
            if (workflowDocTrackingRecord != null) {
              result.add(workflowDocTrackingRecord);
            }
            workflowDocTrackingRecord = new WorkflowDocTrackingRecord();
            MtmWorkflowProgressSystemObjectDAObject mtmWfProgSysObjDAO = new MtmWorkflowProgressSystemObjectDAObject(sessionContainer, dbConn);
            /**
             * @TODO To get the MtmWorkflowProgressSystemObject by the trackID & objectID
             */
            MtmWorkflowProgressSystemObject relatedObject = null;
            List objectList = mtmWfProgSysObjDAO.getListByTrackID(new Integer(tmpTrackID));
            if (!Utility.isEmpty(objectList)) {
              relatedObject = (MtmWorkflowProgressSystemObject) objectList.get(0);
            }
            // MtmWorkflowProgressSystemObject relatedObject =
            // (MtmWorkflowProgressSystemObject)mtmWfProgSysObjDAO.getObjectByTrackID(
            // Integer.valueOf(tmpTrackID) );
            workflowDocTrackingRecord.setRecordCount(totalNumOfRecord);
            workflowDocTrackingRecord.setRowNum(startOffset++);
            workflowDocTrackingRecord.setRelatedObject(relatedObject);
          }
          currentTrackID = tmpTrackID;
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));
          if (!Utility.isEmpty(tmpWorkflowProgress.getTrackID())) {
            String submitter = UserInfoFactory.getUserFullName(getUserIDForWorkflowTrackSubmitter(tmpWorkflowProgress.getTrackID()));
            tmpWorkflowProgress.setSubmitter(submitter);
          }
          // tmpWorkflowProgress.setRecordCount(totalNumOfRecord);
          // tmpWorkflowProgress.setRowNum(startOffset++);

          List userActorList = stepActorDAO.getListByWorkflowStepID(tmpWorkflowProgress.getWorkflowStepID());
          // loop through the userActorList to check if there is a "D" type,
          // which means it's dynamic assign owner,
          // also assume there are already runtime assigned records in the
          // table MTM_WF_DYNAMIC_USER_ACTOR
          List tmpUserActorList = new ArrayList();
          Iterator userActorItr = userActorList.iterator();
          while (userActorItr.hasNext()) {
            MtmWorkflowStepUserActor userActor = (MtmWorkflowStepUserActor) userActorItr.next();
            if (MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN.equals(userActor.getActorType())) {
              MtmWorkflowDynamicUserActorDAObject dynamicActorDAO = new MtmWorkflowDynamicUserActorDAObject(sessionContainer, dbConn);
              List dynamicActors = dynamicActorDAO.getListByWorkflowProgressID(tmpWorkflowProgress.getID());
              if (dynamicActors.size() == 0) {
                // if there is no runtime assigned owner
                // use the "Dynamic Assigned" string
                tmpUserActorList.add(userActor);
                break;
              } else {
                userActorList = new ArrayList();
                Iterator dynamicActorItr = dynamicActors.iterator();
                while (dynamicActorItr.hasNext()) {
                  // TODO: modify MtmWorkflowDynamicUserActor to extends
                  // MtmWorkflowStepUserActor
                  MtmWorkflowDynamicUserActor dynamicActor = (MtmWorkflowDynamicUserActor) dynamicActorItr.next();
                  MtmWorkflowStepUserActor tmpUserActor = new MtmWorkflowStepUserActor();
                  tmpUserActor.setWorkflowStepID(tmpWorkflowProgress.getWorkflowStepID());
                  tmpUserActor.setActorType(dynamicActor.getActorType());
                  tmpUserActor.setActorID(dynamicActor.getActorID());
                  tmpUserActor.setActorName(dynamicActor.getActorName());
                  tmpUserActorList.add(tmpUserActor);
                }
              }
            }
          }
          if (tmpUserActorList.size() > 0) {
            // if there are already runtime assigned owners
            userActorList = null;
            userActorList = tmpUserActorList;
          }

          tmpWorkflowProgress.setUserActorList(userActorList);
          workflowDocTrackingRecord.add(tmpWorkflowProgress);

          MtmWorkflowProgressUserRecordDAObject mtmWorkflowProgressUserRecordDAO = new MtmWorkflowProgressUserRecordDAObject(sessionContainer, dbConn);
          List userList = mtmWorkflowProgressUserRecordDAO.getListByWorkflowProgressID(tmpWorkflowProgress.getID());
          workflowDocTrackingRecord.addWorkflowProgressUserRecord(userList);
        }
        if (workflowDocTrackingRecord != null) {
          result.add(workflowDocTrackingRecord);
        }
        return (result);

      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }
      }
    }
  }

  /**
   * Gets a list of progress for generating document transaction list (for paper document)
   *
   * @param searchForm The ListWorkflowDocThroughUserForm object that contains the document reference number
   * @return List of desired workflow progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.web.ListWorkflowDocThroughUserForm
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized List getListDocThroughUser(AbstractSearchForm searchForm) throws ApplicationException {
    MtmWorkflowProgressSystemObjectDAObject sysObjDAO = new MtmWorkflowProgressSystemObjectDAObject(sessionContainer, dbConn);
    PreparedStatement preStat = null;
    PreparedStatement preStatCnt = null;
    ResultSet rs = null;
    ResultSet rsCnt = null;
    StringBuffer sqlStat = new StringBuffer();
    StringBuffer sqlStatCnt = new StringBuffer();
    List result = new ArrayList();
    int totalNumOfRecord = 0;
    int rowLoopCnt = 0;
    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());
    ListWorkflowDocThroughUserForm listForm = (ListWorkflowDocThroughUserForm) searchForm;

    synchronized (dbConn) {
      try {
        // * get the list, filter with criteria and track id list

        /*
         * SELECT W.WORKFLOW_CODE, P.TRACK_ID, S.STEP_NAME, D.REFERENCE_NO, P.STATUS, U.FULL_NAME FROM WORKFLOW_RECORD W, WORKFLOW_STEP S, WORKFLOW_PROGRESS P,
         * MTM_WF_PROGRESS_SYSTEM_OBJECT O, DMS_DOCUMENT D, MTM_WF_PROGRESS_USER_RECORD PU, USER_RECORD U WHERE W.WORKFLOW_CATEGORY_ID=12 AND
         * W.ID=S.WORKFLOW_RECORD_ID AND S.ID=P.WORKFLOW_STEP_ID AND P.TRACK_ID=O.TRACK_ID AND O.OBJECT_ID=D.ID AND P.ID=PU.WORKFLOW_PROGRESS_ID AND
         * U.ID=PU.USER_RECORD_ID AND (P.CREATOR_ID=3 OR U.ID=3) AND (PU.WORKFLOW_ACTION<>'P' OR (P.STATUS='P' AND PU.USER_RECORD_ID=3) ) ORDER BY P.TRACK_ID,
         * S.STEP_SEQ
         */

        sqlStat.append("SELECT DISTINCT(P2.ID), P2.STATUS, P2.PROGRESS_PRIORITY, P2.TRACK_ID, P2.WORKFLOW_STEP_ID, P2.SEQ_NO, P2.UPDATE_DATE, S.STEP_SEQ, S.STEP_NAME, S.PRIORITY,S.WORKFLOW_RECORD_ID, W.WORKFLOW_CODE, D.DOCUMENT_NAME, D.USER_DEF_1, D.USER_DEF_2, D.USER_DEF_3, D.USER_DEF_4, D.USER_DEF_5, D.USER_DEF_6, D.USER_DEF_7, D.USER_DEF_8, D.USER_DEF_9, D.USER_DEF_10, UDF.USER_DEFINED_TYPE, U.ID SENDER_ID, U.FULL_NAME SENDER_NAME, P2.UPDATER_ID\n");
        sqlStat.append("  FROM WORKFLOW_RECORD W, WORKFLOW_STEP S, WORKFLOW_PROGRESS P, MTM_WF_PROGRESS_SYSTEM_OBJECT O, ((DMS_DOCUMENT D LEFT JOIN DMS_DOCUMENT_INDEX I ON D.ID=I.DOCUMENT_ID) LEFT JOIN SYS_USER_DEFINED_INDEX UDF ON I.USER_DEFINED_FIELD_ID=UDF.ID), MTM_WF_PROGRESS_USER_RECORD PU, USER_RECORD U,\n");
        sqlStat.append("    MTM_WF_PROGRESS_WF_PROGRESS PP, WORKFLOW_PROGRESS P2, MTM_WF_PROGRESS_USER_RECORD PU2, USER_RECORD U2 \n");
        sqlStat.append("WHERE W.WORKFLOW_CATEGORY_ID=?\n");
        sqlStat.append("  AND W.ID=S.WORKFLOW_RECORD_ID\n");
        sqlStat.append("  AND S.ID=P.WORKFLOW_STEP_ID\n");
        sqlStat.append("  AND S.STEP_SEQ=?\n");
        sqlStat.append("  AND S.ACTION_TYPE<>?\n");
        sqlStat.append("  AND P.TRACK_ID=O.TRACK_ID\n");
        sqlStat.append("  AND O.OBJECT_ID=D.ID\n");
        sqlStat.append("  AND P.ID=PU.WORKFLOW_PROGRESS_ID\n");
        sqlStat.append("  AND U.ID=PU.USER_RECORD_ID\n");

        sqlStat.append("  AND P.ID=PP.PARENT_PROGRESS_ID\n");
        sqlStat.append("  AND P2.ID=PP.CHILD_PROGRESS_ID\n");
        sqlStat.append("  AND P2.ID=PU2.WORKFLOW_PROGRESS_ID\n");
        sqlStat.append("  AND U2.ID=PU2.USER_RECORD_ID\n");

        sqlStat.append("  AND (P2.STATUS=? OR PU2.WORKFLOW_ACTION<>?)\n");
        if (!Utility.isEmpty(listForm.getActionTaker()) && !listForm.getActionTaker().equals("-1")) {
          sqlStat.append("  AND (PU.USER_RECORD_ID= ? OR PU2.USER_RECORD_ID=? )\n");
        } else {
          sqlStat.append("  AND (PU.USER_RECORD_ID= ? OR PU2.USER_RECORD_ID=? )\n");
        }
        if (!Utility.isEmpty(listForm.getStatus())) {
          sqlStat.append("  AND (PU.WORKFLOW_ACTION=? OR PU2.WORKFLOW_ACTION=? ) \n");
        }
        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && Utility.isEmpty(listForm.getDatePeriodTo())) {
            sqlStat.append("  AND P.UPDATE_DATE >= to_date(? , 'YYYY-MM-DD HH24:MI:SS') \n");
          } else if (Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
            sqlStat.append("  AND P.UPDATE_DATE <= to_date(? , 'YYYY-MM-DD HH24:MI:SS') \n");
          } else if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
            sqlStat.append("  AND P.UPDATE_DATE BETWEEN to_date(? , 'YYYY-MM-DD HH24:MI:SS') AND to_date(? , 'YYYY-MM-DD HH24:MI:SS') \n");
          }
        } else {
          if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && Utility.isEmpty(listForm.getDatePeriodTo())) {
            sqlStat.append("  AND P.UPDATE_DATE >= ? \n");
          } else if (Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
            sqlStat.append("  AND P.UPDATE_DATE <= ? \n");
          } else if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
            sqlStat.append("  AND P.UPDATE_DATE BETWEEN ? AND ? \n");
          }
        }

        // TODO: Find also the pending progress for the user that is not already
        // in MTM_WF_PROGRESS_USER_RECORD

        // Form the ORDER clause for sorting.
        if (searchForm.isSortable()) {
          String sortAttribute = searchForm.getSortAttribute();
          if (sortAttribute.indexOf(".") < 0) {
            sortAttribute = "P2." + sortAttribute;
          }
          sqlStat.append("ORDER BY " + sortAttribute + " " + searchForm.getSortOrder());
        }
        // sqlStat.append ( "ORDER BY P.TRACK_ID, S.STEP_SEQ\n" );

        // format the sql for any 'LIKE' statement contained
        sqlStat = this.getFormattedSQL(sqlStat.toString());

        // Get total number of record return.
        sqlStatCnt = this.getSelectCountSQL(sqlStat);
        sqlStatCnt = sqlStatCnt.replace(0, 15, "SELECT COUNT(DISTINCT(P2.ID))");
        int i = 1;
        preStatCnt = dbConn.prepareStatement(sqlStatCnt.toString());

        // filter only paper document circulation workflow
        this.setPrepareStatement(preStatCnt, i++, SystemWorkflowConstant.DMS_PAPER_DOCUMENT);

         //  Filter only start step
        this.setPrepareStatement(preStatCnt, i++, new Integer(1));

         //  ignore any automatic task
        this.setPrepareStatement(preStatCnt, i++, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);

        //  filter only pending progress  or finished progress_user
        this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);


        // only pending progress or finished progress_user
        this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);

        if (!Utility.isEmpty(listForm.getActionTaker()) && !listForm.getActionTaker().equals("-1")) {
          this.setPrepareStatement(preStatCnt, i++, listForm.getActionTaker());
          this.setPrepareStatement(preStatCnt, i++, listForm.getActionTaker());
        } else {
          this.setPrepareStatement(preStatCnt, i++, sessionContainer.getUserRecordID());
          this.setPrepareStatement(preStatCnt, i++, sessionContainer.getUserRecordID());
        }
        if (!Utility.isEmpty(listForm.getStatus())) {
          this.setPrepareStatement(preStatCnt, i++, listForm.getStatus());
          this.setPrepareStatement(preStatCnt, i++, listForm.getStatus());
        }
        if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && Utility.isEmpty(listForm.getDatePeriodTo())) {
          this.setPrepareStatement(preStatCnt, i++, listForm.getDatePeriodFrom());
        } else if (Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
          this.setPrepareStatement(preStatCnt, i++, TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
        } else if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
          this.setPrepareStatement(preStatCnt, i++, listForm.getDatePeriodFrom());
          this.setPrepareStatement(preStatCnt, i++, TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
        }

        rsCnt = preStatCnt.executeQuery();
        if (rsCnt.next()) {
          totalNumOfRecord = rsCnt.getInt(1);
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }

        // Retrieve the result in row basis.
        sqlStat = this.getSelectListSQL(sqlStat, startOffset, pageSize);
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        i = 1;

        //   filter only paper document circulation workflow
        this.setPrepareStatement(preStat, i++, SystemWorkflowConstant.DMS_PAPER_DOCUMENT);

        //   Filter only start step
        this.setPrepareStatement(preStat, i++, new Integer(1));

        //  ignore any automatic task
        this.setPrepareStatement(preStat, i++, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);

        // filter only pending progress or finished progress_user
        this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);

        //  filter only pending progress or finished progress_user
        this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);

        if (!Utility.isEmpty(listForm.getActionTaker()) && !listForm.getActionTaker().equals("-1")) {
          this.setPrepareStatement(preStat, i++, listForm.getActionTaker());
          this.setPrepareStatement(preStat, i++, listForm.getActionTaker());
        } else {
          this.setPrepareStatement(preStat, i++, sessionContainer.getUserRecordID());
          this.setPrepareStatement(preStat, i++, sessionContainer.getUserRecordID());
        }
        if (!Utility.isEmpty(listForm.getStatus())) {
          this.setPrepareStatement(preStat, i++, listForm.getStatus());
          this.setPrepareStatement(preStat, i++, listForm.getStatus());
        }
        if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && Utility.isEmpty(listForm.getDatePeriodTo())) {
          this.setPrepareStatement(preStat, i++, listForm.getDatePeriodFrom());
        } else if (Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
          this.setPrepareStatement(preStat, i++, TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
        } else if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
          this.setPrepareStatement(preStat, i++, listForm.getDatePeriodFrom());
          this.setPrepareStatement(preStat, i++, TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
        }

        log.debug("actionTaker=" + listForm.getActionTaker());
        log.debug(preStat.toString());
        rs = preStat.executeQuery();

        this.positionCursor(rs, startOffset, pageSize);
        while (rs.next() && rowLoopCnt < pageSize) {
          WorkflowDocThroughUserRecord throughUserRecord = new WorkflowDocThroughUserRecord();
          throughUserRecord.setID(getResultSetInteger(rs, "ID"));
          throughUserRecord.setStatus(getResultSetString(rs, "STATUS"));
          throughUserRecord.setWorkflowProgressID(getResultSetInteger(rs, "ID"));
          throughUserRecord.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          throughUserRecord.setCreatorID(getResultSetInteger(rs, "SENDER_ID"));
          throughUserRecord.setCreatorName(getResultSetString(rs, "SENDER_NAME"));
          // throughUserRecord.setUpdaterName(getResultSetString(rs,"UPDATER_NAME"));
          throughUserRecord.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          throughUserRecord.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          // throughUserRecord.setActionTaker(getResultSetString(rs, "USER_RECORD_ID"));

          throughUserRecord.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          throughUserRecord.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          throughUserRecord.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          throughUserRecord.setStepName(getResultSetString(rs, "STEP_NAME"));
          throughUserRecord.setPriority(getResultSetString(rs, "PRIORITY"));
          throughUserRecord.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));

          throughUserRecord.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          throughUserRecord.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));

          // throughUserRecord.setRelatedObject(getResultSetObject(rs,
          // "PARAMETER_OBJECT"));
          /**
           * @TODO To get the MtmWorkflowProgressSystemObject by trackID & objectID
           */
          MtmWorkflowProgressSystemObject sysObject = null;
          List objectList = sysObjDAO.getListByTrackID(throughUserRecord.getTrackID());
          if (!Utility.isEmpty(objectList)) {
            sysObject = (MtmWorkflowProgressSystemObject) objectList.get(0);
          }
          throughUserRecord.setRelatedObject(sysObject.getParameterObject());
          // throughUserRecord.setRelatedObject(((MtmWorkflowProgressSystemObject)sysObjDAO.getObjectByTrackID(throughUserRecord.getTrackID())).getParameterObject());
          throughUserRecord.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          throughUserRecord.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          throughUserRecord.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          throughUserRecord.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          throughUserRecord.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          throughUserRecord.setUserDef6(getResultSetString(rs, "USER_DEF_6"));
          throughUserRecord.setUserDef7(getResultSetString(rs, "USER_DEF_7"));
          throughUserRecord.setUserDef8(getResultSetString(rs, "USER_DEF_8"));
          throughUserRecord.setUserDef9(getResultSetString(rs, "USER_DEF_9"));
          throughUserRecord.setUserDef10(getResultSetString(rs, "USER_DEF_10"));
          throughUserRecord.setDocumentProfileName(getResultSetString(rs, "USER_DEFINED_TYPE"));

          throughUserRecord.setRecordCount(totalNumOfRecord);
          throughUserRecord.setRowNum(startOffset++);

          ++rowLoopCnt;
          result.add(throughUserRecord);
        }
        log.debug("result.size()=" + result.size());
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }
      }
    }
  }

  // ADD BY TC FOR SUBQUERY
  public synchronized List getListTrackingByUserRecordID(AbstractSearchForm searchForm) throws ApplicationException {
    MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);
    PreparedStatement preStat = null;
    PreparedStatement preStatCnt = null;
    ResultSet rs = null;
    ResultSet rsCnt = null;
    StringBuffer sqlStat = new StringBuffer();
    StringBuffer sqlStatCnt = new StringBuffer();
    List result = new ArrayList();
    int totalNumOfRecord = 0;
    int rowLoopCnt = 0;
    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());
    String bFormShowFullList = "";
    String userRecordIDs = sessionContainer.getUserRecordID().toString();
    String referenceNumber = "";
    String docReferenceNumber = "";
    String trackIDs = "-1";
    String attachmentName = null;
    String progressIDsByAttachmentName = "-1";
    String taskComment = null;


    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    //SqlstrAndParameters strAndParaTrackIDs = null;
    //SqlstrAndParameters strAndParaProgressIDs = null;

    AbstractQuery query = QueryUtil.createQuery();
    AbstractQuery trackIDsSQL = null;
    AbstractQuery progressIDsByAttachmentNameSQL = null;

    if (searchForm instanceof ListWorkflowProgressForm) {
      ListWorkflowProgressForm listForm = (ListWorkflowProgressForm) searchForm;
      bFormShowFullList = listForm.getShowFullList();
      log.debug("view user: " + listForm.getViewUserRecordID() + ", null? " + Utility.isEmpty(listForm.getViewUserRecordID()));
      if (!Utility.isEmpty(listForm.getViewUserRecordID())) {
        userRecordIDs = listForm.getViewUserRecordID();
      }
      referenceNumber = listForm.getReferenceNumber();
      // get the track ID list by document reference number
      docReferenceNumber = listForm.getDocReferenceNumber();

      if (!Utility.isEmpty(referenceNumber)) {
        trackIDsSQL = this.getTrackIDsSQLByRelatedObject(listForm.getReferenceNumber(),GlobalConstant.RECORD_STATUS_ACTIVE);
      }
      else if (!Utility.isEmpty(docReferenceNumber)) {
        //strAndParaTrackIDs = this.getTrackIDsSQLByRelatedObject(listForm.getDocReferenceNumber(),GlobalConstant.RECORD_STATUS_ACTIVE);
        //trackIDs = strAndParaTrackIDs.getSqlStr();
        trackIDsSQL = this.getTrackIDsSQLByRelatedDMSObject(listForm.getDocReferenceNumber(),GlobalConstant.RECORD_STATUS_ACTIVE);
      }

      // get the progress ID list by attachment name
      attachmentName = listForm.getAttachmentName();
      if (!Utility.isEmpty(attachmentName)) {
        //strAndParaProgressIDs = this.getProgressIDsSQLByAttachmentName(attachmentName);
        //progressIDsByAttachmentName = strAndParaProgressIDs.getSqlStr();
        progressIDsByAttachmentNameSQL = this.getProgressIDsSQLByAttachmentName(attachmentName);
      }

      // get the task comment value
      taskComment = listForm.getTaskComment();

    } else if (searchForm instanceof ListPersonalHomeForm) {
      ListPersonalHomeForm homeForm = (ListPersonalHomeForm) searchForm;
      bFormShowFullList = homeForm.getShowFullList();
      searchForm.setSortAttribute("UPDATE_DATE");
      searchForm.setSortOrder("DESC");
    }

    boolean fullList = GlobalConstant.TRUE.equals(bFormShowFullList);

    synchronized (dbConn) {
      try {
        //B.DESCRIPTION AS WORKFLOW_DESCRIPTION, C.WORKFLOW_CATEGORY_NAME,D.DESCRIPTION AS STEP_DESCRIPTION,A.UPDATE_COUNT,
        query.append("SELECT  A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY,  A.RECORD_STATUS,  A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, B.WORKFLOW_CODE, B.WORKFLOW_VERSION, B.START_DATE, B.END_DATE,  B.WORKFLOW_CATEGORY_ID, B.ID AS WORKFLOW_RECORD_ID, D.STEP_SEQ, D.STEP_NAME, D.ACTION_TYPE,  D.PRIORITY, D.ON_NO_RESPONSE_AFTER, D.ON_NO_RESPONSE_FOR, WSTAGE.STAGE_NAME \n");
        query.append("FROM    WORKFLOW_STEP D LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON D.ID=SS.WORKFLOW_STEP_ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON SS.WORKFLOW_STAGE_ID=WSTAGE.ID, WORKFLOW_RECORD B, SETUP_OPTION_WORKFLOW_CATEGORY C, WORKFLOW_PROGRESS A, \n");
        query.append("                WORKFLOW_PROGRESS WP1, MTM_WF_PROGRESS_USER_RECORD PUR1 \n");
        query.append("WHERE   A.WORKFLOW_STEP_ID = D.ID \n");
        query.append("    AND D.WORKFLOW_RECORD_ID = B.ID \n");
        query.append("    AND B.WORKFLOW_CATEGORY_ID = C.ID \n");
        query.append("    AND A.TRACK_ID = WP1.TRACK_ID \n");
        query.append("    AND WP1.SEQ_NO = 1 \n");
        query.append("    AND WP1.ID = PUR1.WORKFLOW_PROGRESS_ID \n");
        query.append("    AND " + getInSQL("PUR1.USER_RECORD_ID", userRecordIDs) + "\n");
        query.append("    AND B.RECORD_STATUS = ? \n");
        query.append("    AND D.STEP_SEQ <> ? \n");
        //query.append("    AND (SS.RECORD_STATUS = ?  OR SS.RECORD_STATUS IS NULL) \n ");// simon

        //strAndPara.addParameters(GlobalConstant.RECORD_STATUS_ACTIVE);
        //strAndPara.addParameters(WorkflowStep.END_STEP_SEQ_NO);
        //strAndPara.addParameters(GlobalConstant.RECORD_STATUS_ACTIVE);
        int i=1;
        query.setParameter(i++, GlobalConstant.RECORD_STATUS_ACTIVE);
        query.setParameter(i++, WorkflowStep.END_STEP_SEQ_NO);
        //query.setParameter(i++, GlobalConstant.RECORD_STATUS_ACTIVE);
        // search by the document reference number
        if (!Utility.isEmpty(docReferenceNumber) || !Utility.isEmpty(referenceNumber)) {
          //sqlStat.append("        AND " + getInSQLStr("A.ID", trackIDs) + " \n");
          //strAndPara.addAllParameters(strAndParaTrackIDs.getParameters());
          query.append("      AND A.ID IN (");
          query.subQuery(trackIDsSQL);
          query.append("  ) \n");
        }
        // search by the task comment.
        if (!Utility.isEmpty(taskComment)) {
          query.append("        AND ").append(this.getSearchColumn("REASON", "PUR1")).append(" LIKE ? \n");
          query.setParameter(i++, this.getFormattedKeyword(taskComment,"LIKE"));
          //strAndPara.addParameters(this.getFormattedKeyword(taskComment,"LIKE"));
        }

        if (!fullList) {
          query.append("        AND A.COMPLETE_FLAG= ?\n");
          query.append("        AND (A.STATUS=? OR A.STATUS=? OR A.STATUS=?) \n");
          query.append("        AND D.ACTION_TYPE <> ? \n");
          query.setParameter(i++, GlobalConstant.FALSE);
          query.setParameter(i++, WorkflowProgress.STATUS_PENDING);
          query.setParameter(i++, WorkflowProgress.STATUS_IN_PROGRESS);
          query.setParameter(i++, WorkflowProgress.STATUS_LOCK);
          query.setParameter(i++, WorkflowStep.ACTION_TYPE_SUBMIT);
          //strAndPara.addParameters(GlobalConstant.FALSE);
          //strAndPara.addParameters(WorkflowProgress.STATUS_PENDING);
          //strAndPara.addParameters(WorkflowProgress.STATUS_IN_PROGRESS);
          //strAndPara.addParameters(WorkflowProgress.STATUS_LOCK);
          //strAndPara.addParameters(WorkflowStep.ACTION_TYPE_SUBMIT);
        }

        // Form the WHERE clause for filtering.
        if (searchForm.isSearchable()) {
          String searchField = getSearchColumn(searchForm.getBasicSearchField());
          query.append(" AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? \n");
          query.setParameter(i++, this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType()));
          //strAndPara.addParameters(this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType()));
        }


        // search by attachment name.
        if (!Utility.isEmpty(attachmentName)) {
          //sqlStat.append(" AND  " + getInSQLStr("A.ID", progressIDsByAttachmentName) + " \n");
          //strAndPara.addAllParameters(strAndParaProgressIDs.getParameters());
          query.append("   AND A.ID IN (");
          query.subQuery(progressIDsByAttachmentNameSQL);
          query.append(" ) \n");
        }


        query.pack();//Important----------


        // format the sql for any 'LIKE' statement contained
        sqlStat = this.getFormattedSQL(query.toString());

        sqlStat.append(" ORDER BY ");
        // Form the ORDER clause for sorting.
        //set the default obder by progress update date desc
        if(GlobalConstant.NOT_AVAILABLE.equals(searchForm.getSortAttribute() ) ){
          searchForm.setSortAttribute("UPDATE_DATE");
        }
        if (searchForm.isSortable()) {
          String sortAttribute = searchForm.getSortAttribute();
          sortAttribute = WorkflowProgressManager.reCombinateSortAttribute(
              sortAttribute, searchForm.getSortOrder(), "A.");
          sqlStat.append(sortAttribute + " " + searchForm.getSortOrder() + ", ");
        }
        if ("TRACK_ID".indexOf(searchForm.getSortAttribute()) >= 0) {
          sqlStat.append(" A.SEQ_NO " + (!fullList ? "DESC " : "ASC "));
        } else {
          sqlStat.append(" A.TRACK_ID DESC, A.SEQ_NO " + (!fullList ? "DESC " : "ASC "));
        }
        log.debug("sqlStat=" + sqlStat.toString());

        // Get total number of record return.
        sqlStatCnt = this.getSelectCountSQL(sqlStat);// simon-----sqlStatCnt

        preStatCnt = dbConn.prepareStatement(sqlStatCnt.toString());
       //--set parameters-------------------------------------------

        this.setPreparedStatement(preStatCnt, 1, query.getAllParameters());

        rsCnt = preStatCnt.executeQuery();
        if (rsCnt.next()) {
          totalNumOfRecord = rsCnt.getInt(1);
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }

        // Retrieve the result in row basis.
        sqlStat = this.getSelectListSQL(sqlStat, startOffset, pageSize); //ADD By TC
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPreparedStatement(preStat, 1, query.getAllParameters());
        rs = preStat.executeQuery();
        this.positionCursor(rs, startOffset, pageSize);//ADD BY TC
        log.debug("sqlStatCnt=" + sqlStatCnt);
        log.debug("sqlStat=" + sqlStat);

        MtmWorkflowProgressUserRecordDAObject mtmUserRecordDAO = new MtmWorkflowProgressUserRecordDAObject(this.sessionContainer, this.dbConn);

        while (rs.next()) {
          log.debug("rowLoopCnt=" + rowLoopCnt + ",pageSize=" + pageSize);
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();


          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          //tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          //tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          //tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          //tmpWorkflowProgress.setStageName(getResultSetString(rs, "STAGE_NAME"));
          tmpWorkflowProgress.setStageName(this.getStageNameByStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID")));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          //tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));
          tmpWorkflowProgress.setRecordCount(totalNumOfRecord);
          tmpWorkflowProgress.setRowNum(startOffset++);
          ++rowLoopCnt;

          // get the pick up user name
          if (WorkflowProgress.STATUS_IN_PROGRESS.equals(tmpWorkflowProgress.getStatus())) {
            List userNameList = mtmUserRecordDAO.getInProgressUserNameListByWorkflowProgressID(tmpWorkflowProgress.getID());
            tmpWorkflowProgress.setPickUpUserName(userNameList);
          }

          result.add(tmpWorkflowProgress);
        }

        for (int y = 0; y < result.size(); y++) {
          WorkflowProgress tmpWorkflowProgress = (WorkflowProgress) result.get(y);
          List userActorList = stepActorDAO.getListByWorkflowStepID(tmpWorkflowProgress.getWorkflowStepID());
          tmpWorkflowProgress.setUserActorList(userActorList);
          result.set(y, tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }
      }
    }
  }

  /**
   * Gets a list of progress that to be processed by the current user record preset in the SessionContainer object during the creation of the DAObject. <br>
   * The user record can be set by,
   *
   * <pre>
   * sessionContainer.setUserRecord(userRecord);
   * </pre>
   *
   * Basic search can be achieved by,
   *
   * <pre>
   * searchForm.setBasicSearchField(&quot;TRACK_ID&quot;);
   * searchForm.setBasicSearchType(&quot;=&quot;);
   * searchForm.setBasicSearchKeyword(&quot;1&quot;);
   * </pre>
   *
   * If you pass in a ListPersonalHomeForm object, the search is only limited to current user's pending list. If you pass in a ListWorkflowProgressForm object,
   * you can search by invoke the setter method of the following properties, <table border=1 cellspacing=1 cellpadding=1>
   * <tr>
   * <th>Property</th>
   * <th>Description</th>
   * <th>Possible values</th>
   * </tr>
   * <tr>
   * <td>showFullList</td>
   * <td>True if show only proceeded list<br>
   * False if show only pending list</td>
   * <td>{@link com.dcivision.framework.GlobalConstant#TRUE},{@link com.dcivision.framework.GlobalConstant#FALSE}</td>
   * </tr>
   * <tr>
   * <td>deletegateUserRecord</td>
   * <td>use this user rather than that in SessionContainer</td>
   * <td>{@link com.dcivision.user.bean.UserRecord#getID()}</td>
   * </tr>
   * <tr>
   * <td>docReferenceNumber</td>
   * <td>related document reference number</td>
   * <td>{@link com.dcivision.dms.bean.DmsDocument#getReferenceNo()}</td>
   * </tr>
   * <tr>
   * <td>dateSearchField</td>
   * <td>search for arrival/due date</td>
   * <td>{@link com.dcivision.workflow.bean.WorkflowProgress#SEARCH_ARRIVAL_DATE},{@link com.dcivision.workflow.bean.WorkflowProgress#SEARCH_DUE_DATE}</td>
   * </tr>
   * <tr>
   * <td>dateFrom</td>
   * <td>date range of the selected search date type</td>
   * <td>yyyy-MM-dd hh:mm:ss</td>
   * </tr>
   * <tr>
   * <td>dateTo</td>
   * <td>date range of the selected search date type</td>
   * <td>yyyy-MM-dd hh:mm:ss</td>
   * </tr>
   * <tr>
   * <td>fromWhom</td>
   * <td>the workflow submitter</td>
   * <td>{@link com.dcivision.user.bean.UserRecord#getID()}</td>
   * </tr>
   * <tr>
   * <td>priority</td>
   * <td>the task priority</td>
   * <td>{@link com.dcivision.framework.GlobalConstant#PRIORITY_HIGH},{@link com.dcivision.framework.GlobalConstant#PRIORITY_LOW},{@link com.dcivision.framework.GlobalConstant#PRIORITY_MEDIUM}</td>
   * </tr>
   * <tr>
   * <td></td>
   * <td></td>
   * <td></td>
   * </tr>
   * <tr>
   * <td>sortAttribute</td>
   * <td>define which column to be sorted</td>
   * <td>SOWC.*: SETUP_OPTION_WORKFLOW_CATEGORY fields<br>
   * WR.*: WORKFLOW_RECORD fields<br>
   * WS.*: WORKFLOW_STEP fields<br>
   * WP.*: WORKFLOW_PROGRESS fields <br>
   * <br>
   * Please refer to the ParaFLOW data dictionary for the table field names </td>
   * </tr>
   * </table>
   *
   * @param searchForm ListWorkflowProgressForm or ListPersonalHomeForm object
   * @return List of desired progresses
   * @throws ApplicationException
   * @see com.dcivision.workflow.web.ListWorkflowProgressForm
   * @see com.dcivision.framework.web.ListPersonalHomeForm
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  /*
  public synchronized List getListPendingForUser(AbstractSearchForm searchForm) throws ApplicationException {
    MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlGeneral = new StringBuffer(), sqlDynamicUser = new StringBuffer(),sqlDynamicUser1 = new StringBuffer();

    int totalNumOfRecord = 0;

    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());

    UserRecordDAObject userDAO = new UserRecordDAObject(sessionContainer, dbConn);


    Integer userRecordID = getEffectiveUserRecordID(searchForm);
    String bFormShowFullList = getbShowFullList(searchForm);

    setPersonalHomeSort(searchForm);

    synchronized (dbConn) {
      try {
        boolean bFullList = GlobalConstant.TRUE.equals(bFormShowFullList);
        UserRecord userRecord = (UserRecord) userDAO.getObjectByID(userRecordID);

        sqlGeneral = getPendUserSql(searchForm, bFullList, userRecord);
        sqlDynamicUser = getDynamicUserSql(searchForm, bFullList);
        sqlDynamicUser1=getUserFilterBy(searchForm, bFullList);

        int generalCount = getGeneralUserCount(searchForm, bFullList, userRecord);
        int dynamicCount = getDynamicUserCount(searchForm, bFullList, userRecord);
        int dynamicCount1 = getUserCountFilterBy(searchForm, bFullList, userRecord);
        totalNumOfRecord = generalCount + dynamicCount+dynamicCount1;

        sqlGeneral.append(" UNION " + sqlDynamicUser.toString());
        sqlGeneral.append(" UNION " + sqlDynamicUser1.toString());
        // Form the ORDER clause for sorting.
        //set the default order by progress priority desc
        if(GlobalConstant.NOT_AVAILABLE.equals(searchForm.getSortAttribute() ) ){
           searchForm.setSortAttribute("PROGRESS_PRIORITY");
        }
        if (searchForm.isSortable()) {
          String sortAttribute = searchForm.getSortAttribute();
         // if (sortAttribute.indexOf(".") < 0) {
            // sortAttribute = "WP." + sortAttribute;
         // }
          //sqlGeneral.append("ORDER BY " + sortAttribute + " " + searchForm.getSortOrder() + ", DUE_DATE DESC,  UPDATE_DATE DESC ");
          sqlGeneral = this.getUnionOrderSQL(sqlGeneral, sortAttribute, searchForm.getSortOrder());//EDIT BY TC FOR MSSQL ERROR
          //sqlGeneral.append(" , DUE_DATE DESC,  UPDATE_DATE DESC ");
        }

        log.debug("sqlStat: \n" + sqlGeneral.toString());

        // Retrieve the result in row basis.
        sqlGeneral = this.getSelectListSQL(sqlGeneral, startOffset, pageSize);
        log.debug("sqlStat: \n" + sqlGeneral.toString());
        preStat = dbConn.prepareStatement(sqlGeneral.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        int index = setGeneralPreStatement(searchForm, preStat, userRecordID, bFullList);

        // ------------- dynamic assign workflow progress begin -----------
        index=setDynamicPreStatement(searchForm, preStat, userRecordID, bFullList, index);
        setDynamicPreStatementFilterBy(searchForm, preStat, userRecordID, bFullList, index);
        rs = preStat.executeQuery();
        this.positionCursor(rs, startOffset, pageSize);

        List result = getResultList(rs, totalNumOfRecord, searchForm);

        for (int i = 0; i < result.size(); i++) {
          WorkflowProgress tmpWorkflowProgress = (WorkflowProgress) result.get(i);
          List userActorList = stepActorDAO.getListByWorkflowStepID(tmpWorkflowProgress.getWorkflowStepID());
          tmpWorkflowProgress.setUserActorList(userActorList);
          result.set(i, tmpWorkflowProgress);
        }

        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }*/

  /**
   * <p>Get the list of pending progress(s)'s id(s) that current user can read.</p>
   * <p>
   * Relates with {@link WorkflowPermissionManager.getUserPermission4SpecialTask(Integer, Integer, Integer)}
   * and {@link WorkflowRecordDAObject.getWorkflowIDs2Display4CurrentUser()}.
   *
   * NOTE:<code>WorkflowRecordDAObject</code> ignore special dynamic user such as 'k' 'V' etc.
   * </p>
   *
   * <pre>
   * Permission priority hierarchy
   *
   * 1. User
   * 2. Special users with deny permission (submitor\submitor supervisor\previous actor\previous actor supervisor\other preview task actor\other preview task actor supervisor)
   * 3. Special users with allow permission (submitor\submitor supervisor\previous actor\previous actor supervisor\other preview task actor\other preview task actor supervisor)
   * 4. Roles with deny permission (roleA and roleB etc)
   * 5. Roles with allow permission (roleC and roleD etc)
   * 6. Groups with deny permission (groupA and groupB etc)
   * 7. Groups with allow permission (groupC and groupD etc)
   * 8. Every one
   *
   * In the condition there are repeat definition in same priority level, 'DENY' permission is priority.
   * </pre>
   *
   * <p>
   * <b>Permission Inheritance</b>
   *
   * <p>
   * The inherited permission for current account, is equal to the first
   * non-null permission in the object hierarchy, starting at user and
   * proceeding upwards in the hierarchy towards the root permission.
   * Below are four tables with various assigned permission values and the
   * resulting inherited permission according to the above rule.
   * <p>
   * Current account is User A and Role A and Role B and Group A.
   *
   * <p>Example 1</p>
   *
   * <table border=1>
   * <tr><td>Object              </td><td>Assigned Permission of Workflow Record A</td></tr>
   * <tr><td>Every one           </td><td>Allow                                        </td></tr>
   * <tr><td>Group A             </td><td>none                                         </td></tr>
   * <tr><td>Role A              </td><td>none                                         </td></tr>
   * <tr><td>Special user A      </td><td>none                                         </td></tr>
   * <tr><td>User A              </td><td>none                                         </td></tr>
   * <tr><td>Inherited Permission</td><td>Allow                                        </td></tr>
   * </table>
   *
   * <p>
   * In example 1 above, only the root object is assigned a permission. This permission
   * value, of <code>User A</code>, inherite from the root object <code>Every one</code>.
   *
   * <p>Example 2</p>
   * <table border=1>
   * <tr><td>Object              </td><td>Assigned Permission of Workflow Record A</td></tr>
   * <tr><td>Every one           </td><td>Allow                                        </td></tr>
   * <tr><td>Group A             </td><td>none                                         </td></tr>
   * <tr><td>Role A              </td><td>none                                         </td></tr>
   * <tr><td>Special user A      </td><td>none                                         </td></tr>
   * <tr><td>User A              </td><td>Deny                                         </td></tr>
   * <tr><td>Inherited Permission</td><td>Deny                                         </td></tr>
   * </table>
   *
   * <p>
   * In example 2, <code>User A</code> have an assigned permission value.
   * There is no need for permission inheritence.
   *
   * <p>Example 3</p>
   * <table border=1>
   * <tr><td>Object              </td><td>Assigned Permission of Workflow Record A</td></tr>
   * <tr><td>Every one           </td><td>Allow                                        </td></tr>
   * <tr><td>Group A             </td><td>none                                         </td></tr>
   * <tr><td>Role A              </td><td>Allow                                        </td></tr>
   * <tr><td>Special user A      </td><td>none                                         </td></tr>
   * <tr><td>User A              </td><td>none                                         </td></tr>
   * <tr><td>Inherited Permission</td><td>Allow                                        </td></tr>
   * </table>
   *
   * <p>
   * In example 3, the <code>User A</code>'s permission is none,
   * but <code>Role A</code> have an assigned permission value,
   * so inherite permission value from <code>Role A</code>.
   *
   * <p>Example 4</p>
   * <table border=1>
   * <tr><td>Object              </td><td>Assigned Permission of Workflow Record A</td></tr>
   * <tr><td>Every one           </td><td>Allow                                        </td></tr>
   * <tr><td>Group A             </td><td>none                                         </td></tr>
   * <tr><td>Role A              </td><td>Allow                                        </td></tr>
   * <tr><td>Role B              </td><td>Deny                                         </td></tr>
   * <tr><td>Special user A      </td><td>none                                         </td></tr>
   * <tr><td>User A              </td><td>none                                         </td></tr>
   * <tr><td>Inherited Permission</td><td>Deny                                         </td></tr>
   * </table>
   *
   * <p>
   * In example 4, the <code>User A</code>'s permission is none,
   * but <code>Role A</code> and <code>Role B</code> all have an assigned permission value,
   * 'DENY' permission is priority, so inherite permission from <code>Role B</code>.
   *
   * @return a text of string contains pending progress(s)'s id(s) that current user can read,
   *         return null if the list can read is empty.
   * @throws ApplicationException
   */
  private String getProgressIDs2Display4CurrentUser(Integer userRecordID) throws ApplicationException {

    StringBuffer progressIDsCanRead4CurrentUser = new StringBuffer();

    Set progressIDsSetCanRead4User = new HashSet();
    Set progressIDsSetCanRead4UserRead = new HashSet();
    Set progressIDsSetCanRead4UserDeny = new HashSet();

    Set progressIDsSetCanRead4SpecialUser = new HashSet();
    Set progressIDsSetCanRead4SpecialUserRead = new HashSet();
    Set progressIDsSetCanRead4SpecialUserDeny = new HashSet();

    Set progressIDsSetCanRead4Roles = new HashSet();
    Set progressIDsSetCanRead4RolesRead = new HashSet();
    Set progressIDsSetCanRead4RolesDeny = new HashSet();

    Set progressIDsSetCanRead4Groups = new HashSet();
    Set progressIDsSetCanRead4GroupsRead = new HashSet();
    Set progressIDsSetCanRead4GroupsDeny = new HashSet();

    Set progressIDsSetCanRead4Everyone = new HashSet();
    Set progressIDsSetCanRead4EveryoneRead = new HashSet();
    Set progressIDsSetCanRead4EveryoneDeny = new HashSet();

    // Construct the roles and groups of current user.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    StringBuffer userRolesIDs = new StringBuffer();
    StringBuffer userGroupsIDs = new StringBuffer();

    MtmUserRecordUserGroupDAObject userRecordUserGroupDAO = new MtmUserRecordUserGroupDAObject(sessionContainer, dbConn);
    MtmUserRecordUserRoleDAObject userRecordUserRoleDAO = new MtmUserRecordUserRoleDAObject(sessionContainer, dbConn);
    List currentUserRoleList = userRecordUserRoleDAO.getUserRoleListByUserRecordID(userRecordID);
    List currentUserGroupList = userRecordUserGroupDAO.getUserGroupListByUserRecordID(userRecordID);

    if (!Utility.isEmpty(currentUserRoleList)) {
      for (int r = 0; r < currentUserRoleList.size(); r++) {
        if (r != 0) {
          userRolesIDs.append(", ");
        }
        userRolesIDs.append(((UserRole) currentUserRoleList.get(r)).getID());
      }
    }

    if (!Utility.isEmpty(currentUserGroupList)) {
      for (int g = 0; g < currentUserGroupList.size(); g++) {
        if (g != 0) {
          userGroupsIDs.append(", ");
        }
        userGroupsIDs.append(((UserGroup) currentUserGroupList.get(g)).getID());
      }
    }

    // Permission query constructe.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    AbstractQuery permissionQuery = QueryUtil.createQuery();

    AbstractQuery dynamicPermissionQuery = this.getDynamicPermissionQuery(
        userRecordID, userRolesIDs.toString(), userGroupsIDs.toString()
        );

    AbstractQuery generalPermissionQuery = this.getGeneralPermissionQuery(
        userRecordID, userRolesIDs.toString(), userGroupsIDs.toString()
        );

    permissionQuery.subQuery(dynamicPermissionQuery);
    permissionQuery.append("\n UNION \n");
    permissionQuery.subQuery(generalPermissionQuery);
    permissionQuery.pack();

    if (log.isDebugEnabled()) {
      log.debug("Query structure to fetch the progress id(s) contain permission config with current user:\n" +
          permissionQuery.toString());
    }

    PreparedStatement permissionState = null;
    ResultSet permissionRS = null;

    try {
      permissionState = dbConn.prepareStatement(permissionQuery.toString());
      this.setPreparedStatement(permissionState, 1, permissionQuery.getAllParameters());
      permissionRS = permissionState.executeQuery();

      if (Utility.isEmpty(permissionRS)) {
        return ("");
      }

      while (permissionRS.next()) {

        Integer progressID = this.getResultSetInteger(permissionRS, "ID");
        String actorType = this.getResultSetString(permissionRS, "ACTOR_TYPE");
        String permission = this.getResultSetString(permissionRS, "PERMISSION");

        if (Utility.isEmpty(progressID) || Utility.isEmpty(actorType) || Utility.isEmpty(permission)) {
          continue;
        }

        if (permission.indexOf(PermissionManager.READ_PERMISSION) < 0 && permission.indexOf(PermissionManager.DENIED_READ_PERMISSION) < 0) {
          continue;
        }

        // Type of user.
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        if (MtmWorkflowStepUserActor.ACTOR_TYPE_USER.equals(actorType)) {

          // If type of user have been in deny list, it means that no need to check current user have read permission with current record or not.
          if (progressIDsSetCanRead4UserDeny.contains(progressID)) {
            continue;
          }

          // Type of user, remove the definition from roles and groups if exists.
          progressIDsSetCanRead4EveryoneRead.remove(progressID);
          progressIDsSetCanRead4GroupsRead.remove(progressID);
          progressIDsSetCanRead4RolesRead.remove(progressID);
          progressIDsSetCanRead4SpecialUserRead.remove(progressID);

          // Record into user definition.
          progressIDsSetCanRead4User.add(progressID);

          if (permission.indexOf(PermissionManager.READ_PERMISSION) > -1) {
            progressIDsSetCanRead4UserRead.add(progressID);
          }

          // In the condition there are repeat definition in same priority level, 'DENY' permission is priority.
          if (permission.indexOf(PermissionManager.DENIED_READ_PERMISSION) > -1) {
            progressIDsSetCanRead4UserRead.remove(progressID);
            progressIDsSetCanRead4UserDeny.add(progressID);
          }
        }

        // Type of special user
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        boolean isSpecialUser = !MtmWorkflowStepUserActor.ACTOR_TYPE_USER.equals(actorType)
            && !MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE.equals(actorType)
            && !MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP.equals(actorType)
            && !MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE.equals(actorType);
        if (isSpecialUser) {

          if (progressIDsSetCanRead4User.contains(progressID)) {
            continue;
          }

          if (progressIDsSetCanRead4SpecialUserDeny.contains(progressID)) {
            continue;
          }

          progressIDsSetCanRead4EveryoneRead.remove(progressID);
          progressIDsSetCanRead4GroupsRead.remove(progressID);
          progressIDsSetCanRead4RolesRead.remove(progressID);

          progressIDsSetCanRead4SpecialUser.add(progressID);
          if (permission.indexOf(PermissionManager.READ_PERMISSION) > -1) {
            progressIDsSetCanRead4SpecialUserRead.add(progressID);
          }

          if (permission.indexOf(PermissionManager.DENIED_READ_PERMISSION) > -1) {
            progressIDsSetCanRead4SpecialUserRead.remove(progressID);
            progressIDsSetCanRead4SpecialUserDeny.add(progressID);
          }

        }

        // Type of role.
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        if (MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE.equals(actorType)) {

          // If the permission have been definition with user, exit to next.
          if (progressIDsSetCanRead4User.contains(progressID)
              || progressIDsSetCanRead4SpecialUser.contains(progressID)) {
            continue;
          }

          if (progressIDsSetCanRead4RolesDeny.contains(progressID)) {
            continue;
          }

          progressIDsSetCanRead4EveryoneRead.remove(progressID);
          progressIDsSetCanRead4GroupsRead.remove(progressID);

          progressIDsSetCanRead4Roles.add(progressID);
          if (permission.indexOf(PermissionManager.READ_PERMISSION) > -1) {
            progressIDsSetCanRead4RolesRead.add(progressID);
          }

          if (permission.indexOf(PermissionManager.DENIED_READ_PERMISSION) > -1) {
            progressIDsSetCanRead4RolesRead.remove(progressID);
            progressIDsSetCanRead4RolesDeny.add(progressID);
          }
        }

        // Type of group.
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        if (MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP.equals(actorType)) {
          if (progressIDsSetCanRead4User.contains(progressID)
              || progressIDsSetCanRead4SpecialUser.contains(progressID)
              || progressIDsSetCanRead4Roles.contains(progressID)) {
            continue;
          }

          if (progressIDsSetCanRead4GroupsDeny.contains(progressID)) {
            continue;
          }

          progressIDsSetCanRead4EveryoneRead.remove(progressID);

          progressIDsSetCanRead4Groups.add(progressID);
          if (permission.indexOf(PermissionManager.READ_PERMISSION) > -1) {
            progressIDsSetCanRead4GroupsRead.add(progressID);
          }

          if (permission.indexOf(PermissionManager.DENIED_READ_PERMISSION) > -1) {
            progressIDsSetCanRead4GroupsRead.remove(progressID);
            progressIDsSetCanRead4GroupsDeny.add(progressID);
          }
        }

        // Type of every one.
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        if (MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE.equals(actorType)) {
          if (progressIDsSetCanRead4User.contains(progressID)
              || progressIDsSetCanRead4SpecialUser.contains(progressID)
              || progressIDsSetCanRead4Roles.contains(progressID)
              || progressIDsSetCanRead4Groups.contains(progressID)) {
            continue;
          }

          if (progressIDsSetCanRead4EveryoneDeny.contains(progressID)) {
            continue;
          }

          progressIDsSetCanRead4Everyone.add(progressID);
          if (permission.indexOf(PermissionManager.READ_PERMISSION) > -1) {
            progressIDsSetCanRead4EveryoneRead.add(progressID);
          }

          if (permission.indexOf(PermissionManager.DENIED_READ_PERMISSION) > -1) {
            progressIDsSetCanRead4EveryoneRead.remove(progressID);
            progressIDsSetCanRead4EveryoneDeny.add(progressID);
          }
        }
      }

      // Pack up the workflow progress id(s) that current user have permission to read.
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      for (Iterator iter = progressIDsSetCanRead4UserRead.iterator(); iter.hasNext();) {
        progressIDsCanRead4CurrentUser.append(iter.next() + ",");
      }

      for (Iterator iter = progressIDsSetCanRead4SpecialUserRead.iterator(); iter.hasNext();) {
        progressIDsCanRead4CurrentUser.append(iter.next() + ",");
      }

      for (Iterator iter = progressIDsSetCanRead4RolesRead.iterator(); iter.hasNext();) {
        progressIDsCanRead4CurrentUser.append(iter.next() + ",");
      }

      for (Iterator iter = progressIDsSetCanRead4GroupsRead.iterator(); iter.hasNext();) {
        progressIDsCanRead4CurrentUser.append(iter.next() + ",");
      }

      for (Iterator iter = progressIDsSetCanRead4EveryoneRead.iterator(); iter.hasNext();) {
        progressIDsCanRead4CurrentUser.append(iter.next() + ",");
      }

      if (progressIDsCanRead4CurrentUser.length() > 0) {
        return (progressIDsCanRead4CurrentUser.substring(0, progressIDsCanRead4CurrentUser.length() - 1));
      }

      return (null);

    } catch (SQLException sqlE) {
      log.error(sqlE, sqlE);
      throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqlE, sqlE.toString());
    } catch (Exception e) {
      log.error(e, e);
      throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
    } finally {
      try {
        permissionRS.close();
        permissionState.close();
      } catch (Exception ignore) {
      } finally {
        permissionRS = null;
        permissionState = null;
      }
    }
  }

  private AbstractQuery getDynamicPermissionQuery(Integer userRecordID, String userRolesIDs, String userGroupsIDs) {
    AbstractQuery dynamicPermissionQuery = QueryUtil.createSubQuery();

    int queryIndex = 1;

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    dynamicPermissionQuery.append( // Select statement begin.
        "SELECT \n" +
        "WP.ID, \n" +
        "MWDUR.ACTOR_TYPE, MWDUR.PERMISSION \n"
        );
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    dynamicPermissionQuery.append(
        "FROM \n" +
        "WORKFLOW_PROGRESS WP \n" +
        "LEFT JOIN WORKFLOW_STEP WS ON WS.ID = WP.WORKFLOW_STEP_ID \n" +
        "LEFT JOIN MTM_WF_DYNAMIC_USER_ACTOR MWDUR ON MWDUR.WORKFLOW_PROGRESS_ID = WP.ID \n"
        );
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    dynamicPermissionQuery.append(
        "WHERE \n"
        );

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    dynamicPermissionQuery.append(
        "EXISTS \n" +
        "( \n" // Dynamic assigned check,
        );

    dynamicPermissionQuery.subQuery(this.getSubQueryOfDynamicAssignedStepCheck());
    dynamicPermissionQuery.pack();
    queryIndex = dynamicPermissionQuery.getParameterSize() + 1;

    dynamicPermissionQuery.append(
        ") \n"
        );

    // Filter by specified filter rule.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    dynamicPermissionQuery.append(
        "AND \n" +
        "( \n" +
        "  ( \n" +
        "  WS.FILTER_BY IS NULL \n" +
        "  ) \n" +
        "  OR \n" + // If filter rule exist, check if current user is equal with the rule.
        "  ( \n" +
        "  EXISTS \n" +
        "    ( \n"
        );
    dynamicPermissionQuery.subQuery(this.getSubQueryOfEqualFilterRuleCheck(userRecordID));
    dynamicPermissionQuery.pack();
    queryIndex = dynamicPermissionQuery.getParameterSize() + 1;

    dynamicPermissionQuery.append(
        "    ) \n" +
        "  ) \n" +
        ") \n"
        );

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    dynamicPermissionQuery.append( // Workflow progress's status and flag.
        "AND WP.RECORD_STATUS = ? \n" +
        "AND WP.CANCEL_FLAG = ? \n" // TODO: If task is cancel, never display it?
        );

    dynamicPermissionQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    dynamicPermissionQuery.setParameter(queryIndex++, GlobalConstant.FALSE);

    dynamicPermissionQuery.append( // Workflow dynamic actor's status and flag.
        "AND MWDUR.PERMISSION IS NOT NULL \n" + // Permission definition is exists.
        "AND MWDUR.RECORD_STATUS = ? \n"
        );

    dynamicPermissionQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    // Filter by current user and roles and groups.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    dynamicPermissionQuery.append(
        "AND \n" +
        "( \n" +
        "  ( \n" +
        "  MWDUR.ACTOR_TYPE = ? AND MWDUR.ACTOR_ID = ? \n" + // Type of user.
        "  ) \n" +
        "  OR \n" + // Type of every one.
        "  ( \n" +
        "  MWDUR.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE + "' \n" +
        "  ) \n");
    dynamicPermissionQuery.setParameter(queryIndex++, MtmWorkflowStepUserActor.ACTOR_TYPE_USER);
    dynamicPermissionQuery.setParameter(queryIndex++, userRecordID);

    if (!Utility.isEmpty(userRolesIDs)) {
      dynamicPermissionQuery.append(
          "  OR \n" + // Type of role.
          "  ( \n" +
          "  MWDUR.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE + "' AND MWDUR.ACTOR_ID IN (" + userRolesIDs + ") \n" +
          "  ) \n"
          );
    }
    if (!Utility.isEmpty(userGroupsIDs)) {
      dynamicPermissionQuery.append(
          "  OR \n" + // Type of group.
          "  ( \n" +
          "  MWDUR.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP + "' AND MWDUR.ACTOR_ID IN (" + userGroupsIDs + ") \n" +
          "  ) \n"
          );
    }
    dynamicPermissionQuery.append(
        ") \n"
        );
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    return (dynamicPermissionQuery);
  }

  private AbstractQuery getGeneralPermissionQuery(Integer userRecordID, String userRolesIDs, String userGroupsIDs) {
    AbstractQuery generalPermissionQuery = QueryUtil.createSubQuery();

    int queryIndex = 1;

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    generalPermissionQuery.append( // Select statement begin.
        "SELECT \n" +
        "WP.ID, \n" +
        "MWSUA.ACTOR_TYPE, MWSUA.PERMISSION \n"
        );
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    generalPermissionQuery.append(
        "FROM \n" +
        "WORKFLOW_PROGRESS WP \n" +
        "LEFT JOIN WORKFLOW_STEP WS ON WS.ID = WP.WORKFLOW_STEP_ID \n" +
        "LEFT JOIN MTM_WF_STEP_USER_ACTOR MWSUA ON MWSUA.WORKFLOW_STEP_ID = WS.ID \n"
        );
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    generalPermissionQuery.append(
        "WHERE \n"
        );

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    generalPermissionQuery.append(
        "NOT EXISTS \n" +
        "( \n" // Dynamic assigned check,
        );
    generalPermissionQuery.subQuery(this.getSubQueryOfDynamicAssignedStepCheck());
    generalPermissionQuery.pack();
    queryIndex = generalPermissionQuery.getParameterSize() + 1;

    generalPermissionQuery.append(
        ") \n"
        );

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    generalPermissionQuery.append( // Workflow progress's status and flag.
        "AND WP.RECORD_STATUS = ? \n" +
        "AND WP.CANCEL_FLAG = ? \n" // TODO: If task is cancel, never display it?
        );

    generalPermissionQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    generalPermissionQuery.setParameter(queryIndex++, GlobalConstant.FALSE);

    generalPermissionQuery.append(
        "AND WS.RECORD_STATUS = ? \n"
        );
    generalPermissionQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    generalPermissionQuery.append( // Workflow dynamic actor's status and flag.
        "AND MWSUA.PERMISSION IS NOT NULL \n" + // Permission definition is exists.
        "AND MWSUA.RECORD_STATUS = ? \n"
        );

    generalPermissionQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    // Filter by specified filter rule.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    generalPermissionQuery.append(
        "AND \n" +
        "( \n" +
        "  ( \n" +
        "  WS.FILTER_BY IS NULL \n" +
        "  ) \n" +
        "  OR \n" + // If filter rule exist, check if current user is equal with the rule.
        "  ( \n" +
        "  EXISTS \n" +
        "    ( \n"
        );
    generalPermissionQuery.subQuery(this.getSubQueryOfEqualFilterRuleCheck(userRecordID));
    generalPermissionQuery.pack();
    queryIndex = generalPermissionQuery.getParameterSize() + 1;

    generalPermissionQuery.append(
        "    ) \n" +
        "  ) \n" +
        ") \n"
        );

    // Filter by current user and special users and roles and groups.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    generalPermissionQuery.append(
        "AND \n" +

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
        "( \n" +
        "  ( \n" + // Type of user.
        "  MWSUA.ACTOR_TYPE = ? AND MWSUA.ACTOR_ID = ? \n" +
        "  ) \n"
        );

    generalPermissionQuery.setParameter(queryIndex++, MtmWorkflowStepUserActor.ACTOR_TYPE_USER);
    generalPermissionQuery.setParameter(queryIndex++, userRecordID);

    generalPermissionQuery.append(
        // ~~~~~~~~~~~~~~~~~~~~~~~~~
        "  OR \n" + // Type of every one.
        "  ( \n" +
        "  MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE + "' \n" +
        "  ) \n"
        );

    generalPermissionQuery.append(
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~
        "  OR \n" + // Type of special user (submitor).
        "  ( \n" +
        "  MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER + "' \n" +
        "  AND EXISTS \n" + // Check if submitter contain current user.
        "    ( \n"
        );
    generalPermissionQuery.subQuery(this.getSubQueryOfSubmitterOrReportToContainsCurrentUser(MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER, userRecordID));
    generalPermissionQuery.pack();
    queryIndex = generalPermissionQuery.getParameterSize() + 1;
    generalPermissionQuery.append(
        "    ) \n" +
        "  ) \n" +

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        "  OR \n" + // Type of special user (submitor supervisor).
        "  ( \n" +
        "  MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO + "' \n" +
        "  AND EXISTS \n" + // Check if submitor supervisor contain current user.
        "    ( \n"
    );
    generalPermissionQuery.subQuery(this.getSubQueryOfSubmitterOrReportToContainsCurrentUser(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO, userRecordID));
    generalPermissionQuery.pack();
    queryIndex = generalPermissionQuery.getParameterSize() + 1;
    generalPermissionQuery.append(
        "    ) \n" +
        "  ) \n" +

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        "  OR \n" + // Type of special user (Previous actor).
        "  ( \n" +
        "  MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER + "' \n" +
        "  AND EXISTS \n" + // Check if previous actor contain current user.
        "    ( \n"
    );
    generalPermissionQuery.subQuery(this.getSubQueryOfPreviousActionTakerOrReportToContainsCurrentUser(MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER, userRecordID));
    generalPermissionQuery.pack();
    queryIndex = generalPermissionQuery.getParameterSize() + 1;
    generalPermissionQuery.append(
        "    ) \n" +
        "  ) \n" +

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        "  OR \n" + // Type of special user (previous actor supervisor).
        "  ( \n" +
        "  MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER + "' \n" +
        "  AND EXISTS \n" + // Check if previous actor supervisor contain current user.
        "    ( \n"
    );
    generalPermissionQuery.subQuery(this.getSubQueryOfPreviousActionTakerOrReportToContainsCurrentUser(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER, userRecordID));
    generalPermissionQuery.pack();
    queryIndex = generalPermissionQuery.getParameterSize() + 1;
    generalPermissionQuery.append(
        "    ) \n" +
        "  ) \n" +

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        "  OR \n" + // Type of special user (Other preview task actor).
        "  ( \n" +
        "  MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER + "' \n" +
        "  AND EXISTS \n" + // Check if other preview task actor contain current user.
        "    ( \n"
    );
    generalPermissionQuery.subQuery(this.getSubQueryOfStepActionTakerOrReportToContainsCurrentUser(MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER, userRecordID));
    generalPermissionQuery.pack();
    queryIndex = generalPermissionQuery.getParameterSize() + 1;
    generalPermissionQuery.append(
        "    ) \n" +
        "  ) \n" +

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        "  OR \n" + // Type of special user (Other preview task actor supervisor).
        "  ( \n" +
        "  MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER + "' \n" +
        "  AND EXISTS \n" + // Check if other preview task actor supervisor contain current user.
        "    ( \n"
    );
    generalPermissionQuery.subQuery(this.getSubQueryOfStepActionTakerOrReportToContainsCurrentUser(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER, userRecordID));
    generalPermissionQuery.pack();
    queryIndex = generalPermissionQuery.getParameterSize() + 1;
    generalPermissionQuery.append(
        "    ) \n" +
        "  ) \n"
        );

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if (!Utility.isEmpty(userRolesIDs)) {
      generalPermissionQuery.append(
          "  OR \n" + // Type of role.
          "  ( \n" +
          "  MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE + "' AND MWSUA.ACTOR_ID IN (" + userRolesIDs + ") \n" +
          "  ) \n"
          );
    }

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if (!Utility.isEmpty(userGroupsIDs)) {
      generalPermissionQuery.append(
          "  OR \n" + // Type of group.
          "  ( \n" +
          "  MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP + "' AND MWSUA.ACTOR_ID IN (" + userGroupsIDs + ") \n" +
          "  ) \n"
          );
    }
    generalPermissionQuery.append(
        ") \n"
        );
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    return (generalPermissionQuery);
  }

  /**
   * List all the pending progress that current user have permission to read.
   *
   * @param searchForm
   * @return
   * @throws ApplicationException
   */
  public synchronized List getPendingList4UserCanRead(AbstractSearchForm searchForm) throws ApplicationException {

    // Progress list to current user rule:
    // 1. Current user have read permission.
    // 2. Not a automatic task.
    // 3. Not a end step.
    // 4. Not a cancel step.
    // 5. Not a completed progress.
    // 6. Current user have never do or have do but haven't complete.

    List result = new ArrayList();

    // Found out the real user.
    Integer userRecordID = getEffectiveUserRecordID(searchForm);
    // Found out the progress(s)'s id(s) that current user have permission to read.
    String progressIDsCurrentUserCanRead = getProgressIDs2Display4CurrentUser(userRecordID);
    boolean isIncludeDelegateRecord = false;
    if(ListWorkflowProgressForm.class.isAssignableFrom(searchForm.getClass())){
      isIncludeDelegateRecord = ((ListWorkflowProgressForm)searchForm).isIncludeDelegateReocrd();
    }
    if(ListPersonalHomeForm.class.isAssignableFrom(searchForm.getClass())){
      isIncludeDelegateRecord = ((ListPersonalHomeForm)searchForm).isIncludeDelegateReocrd();
    }
    
    if(isIncludeDelegateRecord){
      Integer userDelegationID = null;
      List userDelegationList =getUserDelegationList(userRecordID);
      for(int i=0;i<userDelegationList.size();i++){
        userDelegationID = (Integer) userDelegationList.get(i);
        String progressIDsDelegationUserCanRead = getProgressIDs2Display4CurrentUser(userDelegationID);
        if (!Utility.isEmpty(progressIDsDelegationUserCanRead)) {
          progressIDsCurrentUserCanRead = progressIDsCurrentUserCanRead +","+ progressIDsDelegationUserCanRead;
        }
      }
        progressIDsCurrentUserCanRead = TextUtility.deleteRepeatStr(progressIDsCurrentUserCanRead, ",");
    }
    if (Utility.isEmpty(progressIDsCurrentUserCanRead)) {
      return result;
    }

    // For page split.
    int totalNumOfRecord = 0;
    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());

    // TODO: What type of progress should we display when it is type of full list?
    // boolean isTypeOfFullList = GlobalConstant.TRUE.equals(this.getbShowFullList(searchForm));

    // Filter the search query if it is true.
    boolean isSearchQuery = searchForm.isSearchable();

    PreparedStatement pendingQueryStat = null;
    PreparedStatement pendingQueryCountStat = null;
    ResultSet pendingQueryRS = null;
    ResultSet pendingQueryCountRS = null;

    AbstractQuery pendingProgressQuery = QueryUtil.createQuery();
    int queryIndex = 1;

    // Constructs the query statement.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    pendingProgressQuery.append( // Select statement begin.
        "SELECT \n" +
        "WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, \n" + // Fields from WORKFLOW_PROGRESS begin.
        "WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.SEQ_NO, WP.STATUS, WP.POST_PROGRESS, \n" +
        "WP.DUE_DATE, WP.UPDATE_DATE, WP.NEXT_STEP_DUE_DATES, WP.PROGRESS_PRIORITY, \n" +
        "WP.RECORD_STATUS, WP.CREATOR_ID, WP.CREATE_DATE, \n" +
        "WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, \n" + // Fields from WORKFLOW_RECORD begin.
        "WR.START_DATE, WR.END_DATE, WR.WORKFLOW_CATEGORY_ID, WR.ID WORKFLOW_RECORD_ID, \n" +
        "WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.PRIORITY \n" // Fields from WORKFLOW_STEP begin.
        );

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    pendingProgressQuery.append( // From statement begin.
        "FROM \n" +
        "WORKFLOW_PROGRESS WP \n" +
        "LEFT JOIN WORKFLOW_STEP WS ON WS.ID = WP.WORKFLOW_STEP_ID \n" +
        "LEFT JOIN WORKFLOW_RECORD WR ON WR.ID = WS.WORKFLOW_RECORD_ID \n" +
        "LEFT JOIN MTM_WF_PROGRESS_USER_RECORD MWPUR \n" +
        "ON MWPUR.WORKFLOW_PROGRESS_ID = WP.ID \n" +
        "AND MWPUR.USER_RECORD_ID = ? \n" + // If have done with this progress, list the record with this progress.
        "AND MWPUR.RECORD_STATUS = ? \n" +
        "LEFT JOIN SETUP_OPTION_WORKFLOW_CATEGORY SOWC ON WR.WORKFLOW_CATEGORY_ID = SOWC.ID \n"
        );

    pendingProgressQuery.setParameter(queryIndex++, userRecordID);
    pendingProgressQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    pendingProgressQuery.append("WHERE \n"); // Where statement begin.

    // Filter the permission definition.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    pendingProgressQuery.append( // Permission check begin.
        "WP.ID IN (" + progressIDsCurrentUserCanRead + ") \n" // Permission filter.
        );
    // Filter the special status and flag.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    pendingProgressQuery.append( // Workflow progress's status and flag.
        "AND WP.RECORD_STATUS = ? \n" +
        "AND WP.CANCEL_FLAG = ? \n" + // TODO: If task is cancel, never display it?
        "AND WP.COMPLETE_FLAG = ? \n" +

        "AND (WP.STATUS = ? OR WP.STATUS = ? OR WP.STATUS = ?) \n"
        );

    pendingProgressQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    pendingProgressQuery.setParameter(queryIndex++, GlobalConstant.FALSE);
    pendingProgressQuery.setParameter(queryIndex++, GlobalConstant.FALSE);

    pendingProgressQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_PENDING);
    pendingProgressQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_IN_PROGRESS);
    pendingProgressQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_LOCK);

    pendingProgressQuery.append( // Workflow step's status and flag.
        "AND WS.STEP_SEQ <> ? \n" +
        "AND WS.ACTION_TYPE <> ? \n"
        );

    pendingProgressQuery.setParameter(queryIndex++, WorkflowStep.END_STEP_SEQ_NO); // Filter end step.
    pendingProgressQuery.setParameter(queryIndex++, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO); // Filter auto step.

    pendingProgressQuery.append( // Workflow category's status.
        "AND SOWC.RECORD_STATUS = ? \n"
        );

    pendingProgressQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    pendingProgressQuery.append( // Check if current user have done this progress begin.
        "AND \n" +
        "( \n" +
        "  (MWPUR.WORKFLOW_PROGRESS_ID IS NULL) \n" + // Never do this progress.
        "  OR \n" + // Have do but haven't complete.
        "  ( \n" +
        "  MWPUR.WORKFLOW_ACTION = ? OR MWPUR.WORKFLOW_ACTION = ? OR MWPUR.WORKFLOW_ACTION = ? \n" +
        "  ) \n" + // Make sure the table 'WORKFLOW_PROGRESS' and 'MTM_WF_PROGRESS_USER_RECORD' is one to one relationship.
        ") \n"
        );

    pendingProgressQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_IN_PROGRESS);
    pendingProgressQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_LOCK);
    pendingProgressQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_PENDING);

    // Search query constructor.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if (isSearchQuery) { // If is search query, filter the given query.
      String searchField = getSearchColumn(searchForm.getBasicSearchField(), "WP");
      pendingProgressQuery.append(
          "AND " + searchField + " " + searchForm.getBasicSearchType() + " ? "
          );

      String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
      pendingProgressQuery.setParameter(queryIndex++, searchKeyword);
    }

    // Append the general search statement.
    pendingProgressQuery.subQuery(this.getGeneralSearchSqlStr(searchForm));
    pendingProgressQuery.pack();
    queryIndex = pendingProgressQuery.getParameterSize() + 1;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    StringBuffer pendingProgressStr = new StringBuffer(pendingProgressQuery.toString());
    StringBuffer pendingProgressCountStr = new StringBuffer(pendingProgressStr.toString());

    // Special contructe for pending progress count query.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    pendingProgressCountStr = new StringBuffer("SELECT COUNT(*) FROM (" + pendingProgressStr.toString() + ") UnionCount");
    pendingProgressCountStr = this.getFormattedSQL(pendingProgressCountStr.toString());

    // Special contructe for pending progress query.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if (GlobalConstant.NOT_AVAILABLE.equals(searchForm.getSortAttribute())) {
      searchForm.setSortAttribute("PROGRESS_PRIORITY");
    }

    // Tidy up order statement.
    if (searchForm.isSortable() && !Utility.isEmpty(searchForm.getSortAttribute())) {
      String sortAttribute = searchForm.getSortAttribute();
      sortAttribute = WorkflowProgressManager.reCombinateSortAttribute(sortAttribute,
          searchForm.getSortOrder(), "WP.");

      pendingProgressStr.append("\n ORDER BY " + sortAttribute + " " + searchForm.getSortOrder() + " \n");
    }

    pendingProgressStr = this.getSelectListSQL(pendingProgressStr, startOffset, pageSize);
    pendingProgressStr = this.getFormattedSQL(pendingProgressStr.toString());

    if (log.isDebugEnabled()) {
      log.debug("Query structure to fetch the progress list that current user can read:\n" +
          pendingProgressStr.toString());
    }

    try {
      // Count execute.
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      pendingQueryCountStat = dbConn.prepareStatement(pendingProgressCountStr.toString());
      this.setPreparedStatement(pendingQueryCountStat, 1, pendingProgressQuery.getAllParameters());
      pendingQueryCountRS = pendingQueryCountStat.executeQuery();

      while (!Utility.isEmpty(pendingQueryCountRS) && pendingQueryCountRS.next()) {
        totalNumOfRecord = pendingQueryCountRS.getInt(1);
      }

      // Pending progress query execute.
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      pendingQueryStat = dbConn.prepareStatement(pendingProgressStr.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      this.setPreparedStatement(pendingQueryStat, 1, pendingProgressQuery.getAllParameters());
      pendingQueryRS = pendingQueryStat.executeQuery();

      this.positionCursor(pendingQueryRS, startOffset, pageSize);

      result = getResultList(pendingQueryRS, totalNumOfRecord, searchForm);

      // Pack up the result and return.
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);
      for (int i = 0; i < result.size(); i++) {
        WorkflowProgress workflowProgress = (WorkflowProgress) result.get(i);
        List userActorList = stepActorDAO.getListByWorkflowStepID(workflowProgress.getWorkflowStepID());
        workflowProgress.setUserActorList(userActorList);
        result.set(i, workflowProgress);
      }

      return (result);

    } catch (SQLException sqlE) {
      log.error(sqlE, sqlE);
      throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqlE, sqlE.toString());
    } catch (Exception e) {
      log.error(e, e);
      throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
    } finally {
      try {
        pendingQueryCountRS.close();
        pendingQueryRS.close();
        pendingQueryCountStat.close();
        pendingQueryStat.close();
      } catch (Exception ignore) {
      } finally {
        pendingQueryCountRS = null;
        pendingQueryRS = null;
        pendingQueryCountStat = null;
        pendingQueryStat = null;
      }
    }
  }

  //ADD BY TC FOR SUBQUERY
  /** @deprecated */
  public synchronized List getListPendingForUser(AbstractSearchForm searchForm) throws ApplicationException {
    MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlGeneral = new StringBuffer(),sqlDynamicUser1 = new StringBuffer();

    int totalNumOfRecord = 0;

    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());

    UserRecordDAObject userDAO = new UserRecordDAObject(sessionContainer, dbConn);


    Integer userRecordID = getEffectiveUserRecordID(searchForm);
    String bFormShowFullList = getbShowFullList(searchForm);
    setPersonalHomeSort(searchForm);


    synchronized (dbConn) {
      try {
        //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
        AbstractQuery query = QueryUtil.createQuery();
        boolean bFullList = GlobalConstant.TRUE.equals(bFormShowFullList);
        UserRecord userRecord = (UserRecord) userDAO.getObjectByID(userRecordID);

        //sqlGeneral = getPendUserSql(searchForm, bFullList, userRecord);
        //SqlstrAndParameters tmpStrPara = getPendUserSqlStr(searchForm, bFullList, userRecord);
        //sqlGeneral.append(tmpStrPara.getSqlStr());
        //strAndPara.addAllParameters(tmpStrPara.getParameters());//ADD general parameters

        AbstractQuery pendUserSql = getPendUserSqlStr(searchForm, bFullList, userRecord);
        query.subQuery(pendUserSql);

        //sqlDynamicUser = getDynamicUserSql(searchForm, bFullList);
        //SqlstrAndParameters tmpStrParaDynamicUser = getDynamicUserSqlStr(searchForm, bFullList,userRecord);
        //sqlDynamicUser = new StringBuffer(tmpStrParaDynamicUser.getSqlStr());

        AbstractQuery dynamicUserSql = getDynamicUserSqlStr(searchForm, bFullList,userRecord);



        sqlDynamicUser1=getUserFilterBy(searchForm, bFullList,userRecord);




//        //int generalCount = getGeneralUserCount(searchForm, bFullList, userRecord);
//        int generalCount = getGeneralUserCount(pendUserSql);//ADD BY TC
//
//        //int generalCount = 0;
//       // int dynamicCount = getDynamicUserCount(searchForm, bFullList, userRecord);
//        int dynamicCount = getDynamicUserCount(dynamicUserSql);
//        //int dynamicCount = 0;
//        int dynamicCount1 = getUserCountFilterBy(searchForm, bFullList, userRecord);
//        //int dynamicCount1=0;
//        totalNumOfRecord = generalCount + dynamicCount+dynamicCount1;

        //log.debug("sqlGeneral:"+sqlGeneral.toString());
        //sqlGeneral.append(" UNION " + sqlDynamicUser.toString());
        query.append(" UNION ");
        query.subQuery(dynamicUserSql);
        query.append(" UNION ");
        query.append(sqlDynamicUser1.toString());
        query.pack();
        //sqlGeneral.append(sqlDynamicUser.toString());
        //strAndPara.addAllParameters(tmpStrParaDynamicUser.getParameters());//Add DynamicUser parameters
        //sqlGeneral.append(" UNION " + sqlDynamicUser1.toString());
        // Form the ORDER clause for sorting.
        //set the default order by progress priority desc
        if(GlobalConstant.NOT_AVAILABLE.equals(searchForm.getSortAttribute() ) ){
           searchForm.setSortAttribute("PROGRESS_PRIORITY");
        }
        if (searchForm.isSortable()) {
          String sortAttribute = searchForm.getSortAttribute();
         // if (sortAttribute.indexOf(".") < 0) {
            // sortAttribute = "WP." + sortAttribute;
          //}
          //sqlGeneral.append("ORDER BY " + sortAttribute + " " + searchForm.getSortOrder() + ", DUE_DATE DESC,  UPDATE_DATE DESC ");
          sqlGeneral = this.getUnionOrderSQL(new StringBuffer(query.toString()), sortAttribute, searchForm.getSortOrder());//EDIT BY TC FOR MSSQL ERROR
          //sqlGeneral.append(" , DUE_DATE DESC,  UPDATE_DATE DESC ");
        }

        //format the sql for any 'LIKE' statement contained
        sqlGeneral = this.getFormattedSQL(sqlGeneral.toString());
        StringBuffer tempStr;

        tempStr = this.getFormattedSQL(query.toString());

        StringBuffer  sqlStatCnt ;

        sqlStatCnt = new StringBuffer(" SELECT COUNT(*) FROM ( "+tempStr.toString()+" ) UnionCount ");

        PreparedStatement preStatCnt = dbConn.prepareStatement(sqlStatCnt.toString());

        int cntIndex =this.setPreparedStatement(preStatCnt,1,query.getAllParameters());

        setDynamicPreStatementFilterBy(searchForm, preStatCnt, userRecordID, bFullList, cntIndex);

        ResultSet rsCnt = preStatCnt.executeQuery();
        if (rsCnt.next()) {
          totalNumOfRecord = rsCnt.getInt(1);
        }
        try { rsCnt.close(); } catch (Exception ignore) {} finally { rsCnt = null; }
        try { preStatCnt.close(); } catch (Exception ignore) {} finally { preStatCnt = null; }


        // Retrieve the result in row basis.
        sqlGeneral = this.getSelectListSQL(sqlGeneral, startOffset, pageSize);



        log.debug("sqlStat: \n" + sqlGeneral.toString());
        //strAndPara.setSqlStr(sqlGeneral.toString());

        preStat = dbConn.prepareStatement(sqlGeneral.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);



        //--set parameters----------------

        int index =this.setPreparedStatement(preStat,1,query.getAllParameters());//set Param first----

        //index = setGeneralPreStatement(searchForm, preStat, userRecordID, bFullList,index);

        // ------------- dynamic assign workflow progress begin -----------
          // index=setDynamicPreStatement(searchForm, preStat, userRecordID, bFullList, index);
           setDynamicPreStatementFilterBy(searchForm, preStat, userRecordID, bFullList, index);


         rs = preStat.executeQuery();

        this.positionCursor(rs, startOffset, pageSize);

        List result = getResultList(rs, totalNumOfRecord, searchForm);
        for (int i = 0; i < result.size(); i++) {
          WorkflowProgress tmpWorkflowProgress = (WorkflowProgress) result.get(i);
          List userActorList = stepActorDAO.getListByWorkflowStepID(tmpWorkflowProgress.getWorkflowStepID());
          tmpWorkflowProgress.setUserActorList(userActorList);
          result.set(i, tmpWorkflowProgress);
        }

        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  private void setPersonalHomeSort(AbstractSearchForm searchForm) {
    if (searchForm instanceof ListPersonalHomeForm) {
      searchForm.setSortAttribute("PROGRESS_PRIORITY");
      searchForm.setSortOrder("DESC");
    }
  }

  private String getbShowFullList(AbstractSearchForm searchForm) {
    String bFormShowFullList = "";
    if (searchForm instanceof ListWorkflowProgressForm) {
      ListWorkflowProgressForm listForm = (ListWorkflowProgressForm) searchForm;
      bFormShowFullList = listForm.getShowFullList();

    } else if (searchForm instanceof ListPersonalHomeForm) {
      ListPersonalHomeForm homeForm = (ListPersonalHomeForm) searchForm;
      bFormShowFullList = homeForm.getShowFullList();
      searchForm.setSortAttribute("PROGRESS_PRIORITY");
      searchForm.setSortOrder("DESC");
    }
    return bFormShowFullList;
  }

  private Integer getEffectiveUserRecordID(AbstractSearchForm searchForm) {
    Integer userRecordID = sessionContainer.getUserRecordID();
    if (searchForm instanceof ListWorkflowProgressForm) {
      ListWorkflowProgressForm listForm = (ListWorkflowProgressForm) searchForm;
      if (!Utility.isEmpty(listForm.getDelegateUserRecordID())) {
        userRecordID = TextUtility.parseIntegerObj(listForm.getDelegateUserRecordID());
      }
    }else if(searchForm instanceof ListPersonalHomeForm){
      ListPersonalHomeForm listForm = (ListPersonalHomeForm)searchForm;
      if (!Utility.isEmpty(listForm.getDelegateUserRecordID())) {
        userRecordID = TextUtility.parseIntegerObj(listForm.getDelegateUserRecordID());
      }
    }
    return userRecordID;
  }

  private int getDynamicUserCount(AbstractSearchForm searchForm, boolean bFullList, UserRecord userRecord) throws Exception {
    StringBuffer sqlDynamicUser = getDynamicUserSql(searchForm, bFullList);
    if (searchForm instanceof ListWorkflowProgressForm) {
      sqlDynamicUser.append(getDynamicUserSearchSql(searchForm));
    }
    sqlDynamicUser = this.getFormattedSQL(sqlDynamicUser.toString());
    StringBuffer sqlDynamicUserCnt = getPendingUserProgressCountSql(sqlDynamicUser);
    PreparedStatement preStatDynamicUserCnt = dbConn.prepareStatement(sqlDynamicUserCnt.toString());
    setDynamicPreStatement(searchForm, preStatDynamicUserCnt, userRecord.getID(), bFullList);
    ResultSet rsDynamic = preStatDynamicUserCnt.executeQuery();
    int dynamicCount = 0;
    if (rsDynamic.next()) {
      dynamicCount = rsDynamic.getInt(1);
    }
    return dynamicCount;
  }

  //Add BY TC FOR TEST
  private int getDynamicUserCount(AbstractQuery dynamicUser) throws Exception {
    StringBuffer sqlDynamicUser = null;
    sqlDynamicUser = this.getFormattedSQL(dynamicUser.toString());
    StringBuffer sqlDynamicUserCnt = getPendingUserProgressCountSql(sqlDynamicUser);
    PreparedStatement preStatDynamicUserCnt = dbConn.prepareStatement(sqlDynamicUserCnt.toString());
    this.setPreparedStatement(preStatDynamicUserCnt,1,dynamicUser.getAllParameters());
    ResultSet rsDynamic = preStatDynamicUserCnt.executeQuery();
    int dynamicCount = 0;
    if (rsDynamic.next()) {
      dynamicCount = rsDynamic.getInt(1);
    }
    return dynamicCount;
  }


  private int getGeneralUserCount(AbstractSearchForm searchForm, boolean bFullList, UserRecord userRecord) throws Exception {
    StringBuffer sqlGeneral = getPendUserSql(searchForm, bFullList, userRecord);



    sqlGeneral = this.getFormattedSQL(sqlGeneral.toString());
    StringBuffer sqlGeneralCnt = getPendingUserProgressCountSql(sqlGeneral);
    PreparedStatement preStatGenerCnt = dbConn.prepareStatement(sqlGeneralCnt.toString());
    setGeneralPreStatement(searchForm, preStatGenerCnt, userRecord.getID(), bFullList,1);
    ResultSet rsGeneral = preStatGenerCnt.executeQuery();
    int generalCount = 0;
    if (rsGeneral.next()) {
      generalCount = rsGeneral.getInt(1);
    }
    return generalCount;
  }

  //ADD BY TC FOR TEST
  private int getGeneralUserCount(AbstractQuery generalStrAndPara) throws SQLException{
    StringBuffer sqlGeneral = new StringBuffer(generalStrAndPara.toString());
    StringBuffer sqlGeneralCnt = getPendingUserProgressCountSql(sqlGeneral);
    PreparedStatement preStatGenerCnt = dbConn.prepareStatement(sqlGeneralCnt.toString());
    this.setPreparedStatement(preStatGenerCnt,1,generalStrAndPara.getAllParameters());
    ResultSet rsGeneral = preStatGenerCnt.executeQuery();
    int generalCount = 0;
    if (rsGeneral.next()) {
      generalCount = rsGeneral.getInt(1);
    }
    return generalCount;
  }

  private List getResultList(ResultSet rs, int totalNumOfRecord, AbstractSearchForm searchForm) throws SQLException, Exception, ApplicationException {
    List result = new ArrayList();
    int rowLoopCnt = 0;
    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());
    while (rs.next() && rowLoopCnt < pageSize) {
      WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
      tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
      tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
      tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
      tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
      tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
      tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
      tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
      tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
      tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
      tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
      tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
      /*tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
      tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
      tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
      tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
      tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));*/
      tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
      //tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
      tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
      tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
      //tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
      tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
      tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
      //tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
      tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
      tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
      //tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
      //tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
      tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
      tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
      tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
      tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
      //tmpWorkflowProgress.setStageName(getResultSetString(rs, "STAGE_NAME"));
      tmpWorkflowProgress.setStageName(this.getStageNameByStepID(getResultSetInteger(rs,"WORKFLOW_STEP_ID")));
      tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
      //tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
      tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
      tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
      tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));
      tmpWorkflowProgress.setRecordCount(totalNumOfRecord);
      tmpWorkflowProgress.setRowNum(startOffset++);
      ++rowLoopCnt;

      // get the pick up user name
      MtmWorkflowProgressUserRecordDAObject mtmUserRecordDAO = new MtmWorkflowProgressUserRecordDAObject(this.sessionContainer, this.dbConn);
      if (WorkflowProgress.STATUS_IN_PROGRESS.equals(tmpWorkflowProgress.getStatus())) {
        List userNameList = mtmUserRecordDAO.getInProgressUserNameListByWorkflowProgressID(tmpWorkflowProgress.getID());
        tmpWorkflowProgress.setPickUpUserName(userNameList);
      }
      result.add(tmpWorkflowProgress);
    }
    return result;
  }

  private int setDynamicPreStatement(AbstractSearchForm searchForm, PreparedStatement preStatCnt, Integer userRecordID, boolean bFullList) throws SQLException {
    int i=1;
    // ------------- dynamic assign workflow progress begin -----------
    this.setPrepareStatement(preStatCnt, i++, GlobalConstant.RECORD_STATUS_ACTIVE);
    this.setPrepareStatement(preStatCnt, i++, GlobalConstant.SUBJECT_TYPE_USER);
    this.setPrepareStatement(preStatCnt, i++, GlobalConstant.SUBJECT_TYPE_GROUP);
    this.setPrepareStatement(preStatCnt, i++, GlobalConstant.SUBJECT_TYPE_ROLE);
    if (bFullList) {
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_SUBMIT);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_SUBMIT);
    } else {
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_IN_PROGRESS);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_LOCK);
      this.setPrepareStatement(preStatCnt, i++, GlobalConstant.FALSE);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_IN_PROGRESS);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_LOCK);
    }
    this.setPrepareStatement(preStatCnt, i++, userRecordID.toString());
    // ------------- dynamic assign workflow progress end --------------
    if (searchForm.isSearchable()) {
      String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
      this.setPrepareStatement(preStatCnt, i++, searchKeyword);
    }
    String permissionKeyword = this.getFormattedKeyword(WORKFLOW_PERMISSION_TYPE_EXECUTE, "LIKE");
    this.setPrepareStatement(preStatCnt, i++, permissionKeyword);
    return i;
  }



  private int setGeneralPreStatement(AbstractSearchForm searchForm, PreparedStatement preStatCnt, Integer userRecordID, boolean bFullList,int index) throws SQLException {
    int i = index;
    this.setPrepareStatement(preStatCnt, i++, GlobalConstant.RECORD_STATUS_ACTIVE);
    this.setPrepareStatement(preStatCnt, i++, GlobalConstant.RECORD_STATUS_ACTIVE);
    this.setPrepareStatement(preStatCnt, i++, GlobalConstant.FALSE);
    this.setPrepareStatement(preStatCnt, i++, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
    this.setPrepareStatement(preStatCnt, i++, MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN);
    if (bFullList) {
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_SUBMIT);
    } else {
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_LOCK);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_IN_PROGRESS);
      this.setPrepareStatement(preStatCnt, i++, GlobalConstant.FALSE);
    }
    this.setPrepareStatement(preStatCnt, i++, MtmWorkflowStepUserActor.ACTION_TYPE_EXECUTION);
    this.setPrepareStatement(preStatCnt, i++, MtmWorkflowStepUserActor.ACTOR_TYPE_USER);
    this.setPrepareStatement(preStatCnt, i++, userRecordID.toString());
    if (searchForm.isSearchable()) {
      String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
      this.setPrepareStatement(preStatCnt, i++, searchKeyword);
    }
    String permissionKeyword = this.getFormattedKeyword(WORKFLOW_PERMISSION_TYPE_EXECUTE, "LIKE");
    this.setPrepareStatement(preStatCnt, i++, permissionKeyword);
    return i;
  }


  private StringBuffer getPendingUserProgressCountSql(StringBuffer sqlStat) {
    StringBuffer sqlStatCnt;
    sqlStatCnt = this.getSelectCountSQL(sqlStat);

    // change the "SELECT COUNT(*)" to "SELECT COUNT(DISTINCT WP.ID)"
    StringBuffer sbTmp = sqlStatCnt;
    sqlStatCnt = new StringBuffer("SELECT COUNT(DISTINCT WP.ID) FROM ");

    int idx = sbTmp.indexOf("FROM ");
    sqlStatCnt.append(sbTmp.substring(idx + 5));
    if (sqlStatCnt.indexOf("ORDER BY") >= 0) {
      sqlStatCnt = new StringBuffer(sqlStatCnt.substring(0, sqlStatCnt.indexOf("ORDER BY") - 1));
    }
    return sqlStatCnt;
  }

  private StringBuffer getDynamicUserSearchSql(AbstractSearchForm searchForm) throws ApplicationException {
    String trackIDs = "-1";
    String referenceNumber = "";
    String docReferenceNumber = "";
    String searchDateFrom;
    StringBuffer sqlStat3 = new StringBuffer();
    String searchDateTo;
    ListWorkflowProgressForm wkprogressForm = (ListWorkflowProgressForm) searchForm;

    referenceNumber = wkprogressForm.getReferenceNumber();
    docReferenceNumber = wkprogressForm.getDocReferenceNumber();

    if (!Utility.isEmpty(referenceNumber)) {
      trackIDs = this.getTrackIDsByRelatedObject(wkprogressForm.getReferenceNumber(), GlobalConstant.RECORD_STATUS_ACTIVE);
    }
    else if (!Utility.isEmpty(wkprogressForm.getDocReferenceNumber())){
      trackIDs = this.getTrackIDsByRelatedDMSObject(wkprogressForm.getDocReferenceNumber(), GlobalConstant.RECORD_STATUS_ACTIVE);
    }
    if ((!Utility.isEmpty(wkprogressForm.getDateFrom())) || (!Utility.isEmpty(wkprogressForm.getDateTo()))) {
      String searchField = "";
      if (WorkflowProgress.SEARCH_ARRIVAL_DATE.equals(wkprogressForm.getDateSearchField())) {
        searchField = "WP.CREATE_DATE";
        searchDateFrom = wkprogressForm.getDateFrom();
        searchDateTo = wkprogressForm.getDateTo();

        sqlStat3.append(" AND ");
        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }

      } else if (WorkflowProgress.SEARCH_DUE_DATE.equals(wkprogressForm.getDateSearchField())) {
        sqlStat3.append(" AND  (");
        searchField = "WS.ON_NO_RESPONSE_AFTER";
        searchDateFrom = wkprogressForm.getDateFrom();
        searchDateTo = wkprogressForm.getDateTo();

        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }

        sqlStat3.append(" OR ");

        switch (DataSourceFactory.getDatabaseType()) {
        case DataSourceFactory.DB_MYSQL:
          searchField = "DATE_ADD(WP.CREATE_DATE, INTERVAL WS.ON_NO_RESPONSE_FOR DAY)";
          break;
        case DataSourceFactory.DB_ORACLE:
          searchField = "(WP.CREATE_DATE +  WS.ON_NO_RESPONSE_FOR)";
          break;
        case DataSourceFactory.DB_MSSQL:
          searchField = "DATEADD('d',WS.ON_NO_RESPONSE,WP.CREATE_DATE)";
          break;
        }

        // searchField = "DATE_ADD(WP.CREATE_DATE, INTERVAL
        // WS.ON_NO_RESPONSE_FOR DAY)";

        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }

        sqlStat3.append(" OR ");
        searchField = "WP.DUE_DATE";
        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat3.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }

        sqlStat3.append(" ) ");
      }

    }

    // search by who send the workflow
    if (!Utility.isEmpty(wkprogressForm.getFromWhom()) && !wkprogressForm.getFromWhom().equals("-1")) {
      sqlStat3.append(" AND ");
      sqlStat3.append("WP.CREATOR_ID = " + wkprogressForm.getFromWhom() + " ");
    }

    // search by the priority of the workflow
    if (!Utility.isEmpty(wkprogressForm.getPriority())) {
      sqlStat3.append(" AND ");
      sqlStat3.append("WP.PROGRESS_PRIORITY = '" + wkprogressForm.getPriority() + "'");
    }

    // search by the document reference number
    if (!Utility.isEmpty(referenceNumber)
        || !Utility.isEmpty(docReferenceNumber)) {
      sqlStat3.append("        AND " + getInSQL("WP.ID", trackIDs) + " \n");
    }

    return sqlStat3;
  }


  /**
   * getDynamicUserSearchSqlStr
   * get the subQuery of method getDynamicUserSearchSql
   * @param searchForm
   * @param docReferenceNumber
   * @param trackIDs
   * @return
   */
  private AbstractQuery getDynamicUserSearchSqlStr(AbstractSearchForm searchForm){

    String referenceNumber = "";
    String docReferenceNumber = "";
    AbstractQuery subQuery = new SubQuery();
    String searchDateFrom;

    String searchDateTo;
    ListWorkflowProgressForm wkprogressForm = (ListWorkflowProgressForm) searchForm;

    referenceNumber = wkprogressForm.getReferenceNumber();
    docReferenceNumber = wkprogressForm.getDocReferenceNumber();

    if ((!Utility.isEmpty(wkprogressForm.getDateFrom())) || (!Utility.isEmpty(wkprogressForm.getDateTo()))) {
      String searchField = "";
      if (WorkflowProgress.SEARCH_ARRIVAL_DATE.equals(wkprogressForm.getDateSearchField())) {
        searchField = "WP.CREATE_DATE";
        searchDateFrom = wkprogressForm.getDateFrom();
        searchDateTo = wkprogressForm.getDateTo();

        subQuery.append(" AND ");
        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }

      } else if (WorkflowProgress.SEARCH_DUE_DATE.equals(wkprogressForm.getDateSearchField())) {
        subQuery.append(" AND  (");
        searchField = "WS.ON_NO_RESPONSE_AFTER";
        searchDateFrom = wkprogressForm.getDateFrom();
        searchDateTo = wkprogressForm.getDateTo();

        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }

        subQuery.append(" OR ");

        switch (DataSourceFactory.getDatabaseType()) {
        case DataSourceFactory.DB_MYSQL:
          searchField = "DATE_ADD(WP.CREATE_DATE, INTERVAL WS.ON_NO_RESPONSE_FOR DAY)";
          break;
        case DataSourceFactory.DB_ORACLE:
          searchField = "(WP.CREATE_DATE +  WS.ON_NO_RESPONSE_FOR)";
          break;
        case DataSourceFactory.DB_MSSQL:
          searchField = "DATEADD('d',WS.ON_NO_RESPONSE,WP.CREATE_DATE)";
          break;
        }

        // searchField = "DATE_ADD(WP.CREATE_DATE, INTERVAL
        // WS.ON_NO_RESPONSE_FOR DAY)";

        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }

        subQuery.append(" OR ");
        searchField = "WP.DUE_DATE";
        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }

        subQuery.append(" ) ");
      }

    }

    // search by who send the workflow
    if (!Utility.isEmpty(wkprogressForm.getFromWhom()) && !wkprogressForm.getFromWhom().equals("-1")) {
      subQuery.append(" AND ");
      subQuery.append("WP.CREATOR_ID = " + wkprogressForm.getFromWhom() + " ");
    }

    // search by the priority of the workflow
    if (!Utility.isEmpty(wkprogressForm.getPriority())) {
      subQuery.append(" AND ");
      subQuery.append("WP.PROGRESS_PRIORITY = '" + wkprogressForm.getPriority() + "'");
    }

    if (!Utility.isEmpty(referenceNumber)) {
      subQuery.append("          AND WP.ID IN ( ");
      subQuery.subQuery(getTrackIDsSQLByRelatedObject(wkprogressForm.getReferenceNumber(), GlobalConstant.RECORD_STATUS_ACTIVE));
      subQuery.append(" )\n");
    }
    // search by the document reference number
    else if (!Utility.isEmpty(docReferenceNumber)) {
      subQuery.append("          AND WP.ID IN ( ");
      subQuery.subQuery(getTrackIDsSQLByRelatedObject(wkprogressForm.getDocReferenceNumber(), GlobalConstant.RECORD_STATUS_ACTIVE));
      subQuery.append(" )\n");
    }

    subQuery.pack();
    return subQuery;
  }

  private StringBuffer getDynamicUserSql(AbstractSearchForm searchForm, boolean bFullList) throws ApplicationException {

    String progressIDs = "-1";

    //get the completed progress ID string for the dynamic assign user by the user record ID
    MtmWorkflowProgressUserRecordDAObject userRecordDAO = new MtmWorkflowProgressUserRecordDAObject(this.sessionContainer,this.dbConn);
    progressIDs = userRecordDAO.getCompletedProgressIDListByUserRecordID(this.sessionContainer.getUserRecordID());

    StringBuffer sqlStat3 = new StringBuffer();
    sqlStat3.append(" SELECT  DISTINCT WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.SEQ_NO, WP.STATUS, WP.POST_PROGRESS, WP.DUE_DATE, WP.NEXT_STEP_DUE_DATES, WP.PROGRESS_PRIORITY, WP.USER_DEF_1, WP.USER_DEF_2, WP.USER_DEF_3, WP.USER_DEF_4, WP.USER_DEF_5, WP.RECORD_STATUS, WP.UPDATE_COUNT, WP.CREATOR_ID, WP.CREATE_DATE, WP.UPDATER_ID, WP.UPDATE_DATE AS UPDATE_DATE, WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR, WSTAGE.STAGE_NAME  \n");
    sqlStat3.append(" FROM WORKFLOW_RECORD WR, WORKFLOW_STEP WS LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON WS.ID=SS.WORKFLOW_STEP_ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON  SS.WORKFLOW_STAGE_ID=WSTAGE.ID, WORKFLOW_PROGRESS WP ");
    sqlStat3.append("      LEFT JOIN MTM_WF_PROGRESS_USER_RECORD MWPUR ON WP.ID = MWPUR.WORKFLOW_PROGRESS_ID   \n");
    sqlStat3.append("      , MTM_WF_DYNAMIC_USER_ACTOR DUA, SETUP_OPTION_WORKFLOW_CATEGORY SOWC, \n");
    sqlStat3.append("      USER_RECORD U \n");
    sqlStat3.append("      LEFT JOIN MTM_USER_RECORD_USER_GROUP UG ON U.ID = UG.USER_RECORD_ID AND UG.RECORD_STATUS = U.RECORD_STATUS \n");
    sqlStat3.append("      LEFT JOIN MTM_USER_RECORD_USER_ROLE UR ON U.ID = UR.USER_RECORD_ID AND UR.RECORD_STATUS = U.RECORD_STATUS \n");
    sqlStat3.append("      LEFT JOIN MTM_USER_GROUP_USER_ROLE GR ON UG.USER_GROUP_ID = GR.USER_GROUP_ID AND GR.RECORD_STATUS = U.RECORD_STATUS \n");
    sqlStat3.append(" WHERE WR.ID = WS.WORKFLOW_RECORD_ID \n");
    sqlStat3.append(" AND WS.ID = WP.WORKFLOW_STEP_ID \n");
    sqlStat3.append(" AND WR.WORKFLOW_CATEGORY_ID = SOWC.ID \n");
    sqlStat3.append(" AND WR.RECORD_STATUS = DUA.RECORD_STATUS \n");
    sqlStat3.append(" AND WS.RECORD_STATUS = DUA.RECORD_STATUS \n");
    sqlStat3.append(" AND WS.filter_by is null \n");
    sqlStat3.append(" AND SOWC.RECORD_STATUS = DUA.RECORD_STATUS \n");
    sqlStat3.append(" AND U.RECORD_STATUS = DUA.RECORD_STATUS \n");
    sqlStat3.append(" AND DUA.WORKFLOW_PROGRESS_ID = WP.ID \n");
    sqlStat3.append(" AND DUA.RECORD_STATUS = ? \n"); // 'A'
    sqlStat3.append(" AND ( (DUA.ACTOR_TYPE = ? AND DUA.ACTOR_ID = U.ID) OR \n"); // 'U'
    sqlStat3.append("       (DUA.ACTOR_TYPE = ? AND DUA.ACTOR_ID = UG.USER_GROUP_ID) OR \n"); // 'G'
    sqlStat3.append("       (DUA.ACTOR_TYPE = ? AND (DUA.ACTOR_ID = GR.USER_ROLE_ID OR DUA.ACTOR_ID = UR.USER_ROLE_ID)) \n"); // 'R'
    sqlStat3.append("     ) \n");
    sqlStat3.append(" AND (MWPUR.WORKFLOW_PROGRESS_ID IS NULL OR MWPUR.WORKFLOW_PROGRESS_ID = WP.ID) AND \n");

    if (bFullList) {
      sqlStat3.append("        WP.STATUS <> ? AND \n");
      sqlStat3.append("        MWPUR.WORKFLOW_ACTION <> ? AND \n");
    } else {
      sqlStat3.append("        (WP.STATUS = ? OR WP.STATUS = ? OR WP.STATUS = ?) AND \n");
      sqlStat3.append("        WP.COMPLETE_FLAG = ? AND \n");
      sqlStat3.append("        (WS.WORKFLOW_RULE = '*' OR MWPUR.WORKFLOW_ACTION IS NULL OR MWPUR.WORKFLOW_ACTION = ? OR MWPUR.WORKFLOW_ACTION = ? OR MWPUR.WORKFLOW_ACTION = ? ) AND \n"); // 'P', 'I', 'L'
      sqlStat3.append("        WP.ID NOT IN (" + progressIDs + ") AND \n");
    }
    sqlStat3.append("  U.ID = ?  \n");// user_record_id

    // ##################################################################
    // Form the WHERE clause for filtering.
    if (searchForm.isSearchable()) {
      String searchField = getSearchColumn(searchForm.getBasicSearchField(), "WP");
      sqlStat3.append("AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? ");
    }

    if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_MYSQL) {
      sqlStat3.append("AND  BINARY DUA.PERMISSION LIKE  ? ");
    } else {
      sqlStat3.append("AND  DUA.PERMISSION LIKE  ? ");
    }

    if (searchForm instanceof ListWorkflowProgressForm) {
      sqlStat3.append(getDynamicUserSearchSql(searchForm));
      }

    return sqlStat3;
  }


  /**
   * getDynamicUserSqlStr
   * get the subQuery of the method getDynamicUserSql
   * @param searchForm
   * @param bFullList
   * @param userRecord
   * @return
   * @throws ApplicationException
   */
  public AbstractQuery getDynamicUserSqlStr(AbstractSearchForm searchForm, boolean bFullList,UserRecord userRecord) throws ApplicationException{

    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    AbstractQuery subQuery = new SubQuery();
    //String progressIDs = "-1";

    //SqlstrAndParameters strAndParaprogressIDs = getCompletedProgressIDListSQLByUserRecordID(this.sessionContainer.getUserRecordID());
    //String progressIDsSQL = strAndParaprogressIDs.getSqlStr();
    //SqlstrAndParameters strAndParaUserSearch = null;
    UserDelegationDAObject delegateDAO = new UserDelegationDAObject(this.sessionContainer,this.dbConn);
    List delegateUserList = delegateDAO.getListDelegatedToUser();
    List userIDList = new ArrayList();
    userIDList.add(userRecord.getID());
    try {
      if(searchForm instanceof ListWorkflowProgressForm&&((ListWorkflowProgressForm)searchForm).isIncludeDelegateReocrd()){
        userIDList.addAll(Utility.getPropertyList(delegateUserList, "sourceUserID"));
      }
    } catch (Exception e) {

    }
    StringBuffer userIDsStr = new StringBuffer();
    for(int i=0;i<userIDList.size();i++){
      if(i==0){
        userIDsStr.append(userIDList.get(i).toString());
      }else{
        userIDsStr.append(" , ").append(userIDList.get(i).toString());
      }
    }
    AbstractQuery strAndParaprogressIDs = getCompletedProgressIDListSQLByUserRecordID(this.sessionContainer.getUserRecordID());
    //StringBuffer sqlStat3 = new StringBuffer();
    //sqlStat3.append(" SELECT  DISTINCT WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.SEQ_NO, WP.STATUS, WP.POST_PROGRESS, WP.DUE_DATE, WP.NEXT_STEP_DUE_DATES, WP.PROGRESS_PRIORITY, WP.USER_DEF_1, WP.USER_DEF_2, WP.USER_DEF_3, WP.USER_DEF_4, WP.USER_DEF_5, WP.RECORD_STATUS, WP.UPDATE_COUNT, WP.CREATOR_ID, WP.CREATE_DATE, WP.UPDATER_ID, WP.UPDATE_DATE AS UPDATE_DATE, WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR, WSTAGE.STAGE_NAME  \n");
    subQuery.append("SELECT  WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.SEQ_NO, WP.STATUS, WP.POST_PROGRESS, WP.DUE_DATE, WP.UPDATE_DATE AS UPDATE_DATE, WP.NEXT_STEP_DUE_DATES, WP.PROGRESS_PRIORITY,  WP.RECORD_STATUS,  WP.CREATOR_ID, WP.CREATE_DATE, WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE,   WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE,  WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR, WSTAGE.STAGE_NAME \n");
    subQuery.append(" FROM WORKFLOW_RECORD WR, WORKFLOW_STEP WS LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON SS.WORKFLOW_STEP_ID = WS.ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON WSTAGE.ID = SS.WORKFLOW_STAGE_ID, WORKFLOW_PROGRESS WP ");
    subQuery.append("      LEFT JOIN MTM_WF_PROGRESS_USER_RECORD MWPUR ON WP.ID = MWPUR.WORKFLOW_PROGRESS_ID   \n");
    subQuery.append("      , MTM_WF_DYNAMIC_USER_ACTOR DUA, SETUP_OPTION_WORKFLOW_CATEGORY SOWC, \n");
    subQuery.append("      USER_RECORD U \n");
    subQuery.append("      LEFT JOIN MTM_USER_RECORD_USER_GROUP UG ON U.ID = UG.USER_RECORD_ID AND UG.RECORD_STATUS = U.RECORD_STATUS \n");
    subQuery.append("      LEFT JOIN MTM_USER_RECORD_USER_ROLE UR ON U.ID = UR.USER_RECORD_ID AND UR.RECORD_STATUS = U.RECORD_STATUS \n");
    subQuery.append("      LEFT JOIN MTM_USER_GROUP_USER_ROLE GR ON UG.USER_GROUP_ID = GR.USER_GROUP_ID AND GR.RECORD_STATUS = U.RECORD_STATUS \n");
    subQuery.append(" WHERE WR.ID = WS.WORKFLOW_RECORD_ID \n");
    subQuery.append(" AND WS.ID = WP.WORKFLOW_STEP_ID \n");
    subQuery.append(" AND WR.WORKFLOW_CATEGORY_ID = SOWC.ID \n");
    subQuery.append(" AND WR.RECORD_STATUS = DUA.RECORD_STATUS \n");
    subQuery.append(" AND WS.RECORD_STATUS = DUA.RECORD_STATUS \n");
    subQuery.append(" AND WS.filter_by is null \n");
    subQuery.append(" AND SOWC.RECORD_STATUS = DUA.RECORD_STATUS \n");
    subQuery.append(" AND U.RECORD_STATUS = DUA.RECORD_STATUS \n");
    subQuery.append(" AND DUA.WORKFLOW_PROGRESS_ID = WP.ID \n");
    subQuery.append(" AND DUA.RECORD_STATUS = ? \n"); // 'A'
    subQuery.append(" AND ( (DUA.ACTOR_TYPE = ? AND DUA.ACTOR_ID = U.ID) OR \n"); // 'U'
    subQuery.append("       (DUA.ACTOR_TYPE = ? AND DUA.ACTOR_ID = UG.USER_GROUP_ID) OR \n"); // 'G'
    subQuery.append("       (DUA.ACTOR_TYPE = ? AND (DUA.ACTOR_ID = GR.USER_ROLE_ID OR DUA.ACTOR_ID = UR.USER_ROLE_ID)) \n"); // 'R'
    subQuery.append("     ) \n");
    //subQuery.append(" AND (MWPUR.WORKFLOW_PROGRESS_ID IS NULL OR MWPUR.WORKFLOW_PROGRESS_ID = WP.ID) AND \n");
    //subQuery.append(" AND (MWPUR.WORKFLOW_PROGRESS_ID IS NULL OR MWPUR.USER_RECORD_ID <> ?) \n");
    subQuery.append(" AND NOT EXISTS (SELECT 'X' \n");
    subQuery.append(" FROM  MTM_WF_PROGRESS_USER_RECORD PUR \n");
    subQuery.append(" WHERE PUR.WORKFLOW_PROGRESS_ID = WP.ID \n");
    subQuery.append(" AND PUR.USER_RECORD_ID = ? \n");
    subQuery.append(" AND PUR.WORKFLOW_ACTION = ?) AND \n");

    if (bFullList) {
      subQuery.append("        WP.STATUS <> ? AND \n");
      subQuery.append("        MWPUR.WORKFLOW_ACTION <> ? AND \n");
    } else {
      subQuery.append("        (WP.STATUS = ? OR WP.STATUS = ? OR WP.STATUS = ?) AND \n");
      subQuery.append("        WP.COMPLETE_FLAG = ? AND \n");
      //subQuery.append("        (WS.WORKFLOW_RULE = '*' OR MWPUR.WORKFLOW_ACTION IS NULL OR MWPUR.WORKFLOW_ACTION = ? OR MWPUR.WORKFLOW_ACTION = ? OR MWPUR.WORKFLOW_ACTION = ? ) AND \n"); // 'P', 'I', 'L'
      //subQuery.append(" "+getNotInSQLStr("WP.ID",progressIDsSQL)+" AND \n ");
      subQuery.append(" WP.ID NOT IN (").subQuery(strAndParaprogressIDs).append(" ) AND \n");
    }
      subQuery.append(this.getInSQL("U.ID", userIDsStr.toString()));


    // ##################################################################
    // Form the WHERE clause for filtering.
    if (searchForm.isSearchable()) {
      String searchField = getSearchColumn(searchForm.getBasicSearchField(), "WP");
      subQuery.append("AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? ");
    }

    if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_MYSQL) {
      subQuery.append("AND  BINARY DUA.PERMISSION LIKE  ? ");
    } else {
      subQuery.append("AND  DUA.PERMISSION LIKE  ? ");
    }

    if (searchForm instanceof ListWorkflowProgressForm) {
      //strAndParaUserSearch =  getDynamicUserSearchSqlStr(searchForm, docReferenceNumber, trackIDs);
      //subQuery.append(strAndParaUserSearch.getSqlStr());
      subQuery.subQuery(getDynamicUserSearchSqlStr(searchForm));
    }


    //---set Params--
    int i=1;
    //strAndPara.addParameters(GlobalConstant.RECORD_STATUS_ACTIVE);
    //strAndPara.addParameters(GlobalConstant.SUBJECT_TYPE_USER);
    //strAndPara.addParameters(GlobalConstant.SUBJECT_TYPE_GROUP);
    //strAndPara.addParameters(GlobalConstant.SUBJECT_TYPE_ROLE);
    subQuery.setParameter(i++, GlobalConstant.RECORD_STATUS_ACTIVE);
    subQuery.setParameter(i++, GlobalConstant.SUBJECT_TYPE_USER);
    subQuery.setParameter(i++, GlobalConstant.SUBJECT_TYPE_GROUP);
    subQuery.setParameter(i++, GlobalConstant.SUBJECT_TYPE_ROLE);
    subQuery.setParameter(i++, userRecord.getID());
    subQuery.setParameter(i++, WorkflowProgress.STATUS_GENERAL_ACCOMPLISHMENT);
    if (bFullList) {
      //strAndPara.addParameters(WorkflowProgress.STATUS_SUBMIT);
      //strAndPara.addParameters(WorkflowProgress.STATUS_SUBMIT);
      subQuery.setParameter(i++, WorkflowProgress.STATUS_SUBMIT);
      subQuery.setParameter(i++, WorkflowProgress.STATUS_SUBMIT);
    }else{
      //strAndPara.addParameters(WorkflowProgress.STATUS_PENDING);
      //strAndPara.addParameters(WorkflowProgress.STATUS_IN_PROGRESS);
      //strAndPara.addParameters(WorkflowProgress.STATUS_LOCK);
      //strAndPara.addParameters(GlobalConstant.FALSE);
      //strAndPara.addParameters(WorkflowProgress.STATUS_PENDING);
      //strAndPara.addParameters(WorkflowProgress.STATUS_IN_PROGRESS);
      //strAndPara.addParameters(WorkflowProgress.STATUS_LOCK);
      //strAndPara.addAllParameters(strAndParaprogressIDs.getParameters());
      subQuery.setParameter(i++, WorkflowProgress.STATUS_PENDING);
      subQuery.setParameter(i++, WorkflowProgress.STATUS_IN_PROGRESS);
      subQuery.setParameter(i++, WorkflowProgress.STATUS_LOCK);
      subQuery.setParameter(i++, GlobalConstant.FALSE);
      //subQuery.setParameter(i++, WorkflowProgress.STATUS_PENDING);
      //subQuery.setParameter(i++, WorkflowProgress.STATUS_IN_PROGRESS);
      //subQuery.setParameter(i++, WorkflowProgress.STATUS_LOCK);
    }
      //strAndPara.addParameters(userRecord.getID());
      //subQuery.setParameter(i++, userRecord.getID());

   if (searchForm.isSearchable()) {
     String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
     //strAndPara.addParameters(searchKeyword);
     subQuery.setParameter(i++, searchKeyword);
   }
    String permissionKeyword = this.getFormattedKeyword(WORKFLOW_PERMISSION_TYPE_EXECUTE, "LIKE");
    //strAndPara.addParameters(permissionKeyword);
    subQuery.setParameter(i++, permissionKeyword);

   //if (searchForm instanceof ListWorkflowProgressForm) {
     //strAndPara.addAllParameters(strAndParaUserSearch.getParameters());
   //}

    //strAndPara.setSqlStr(sqlStat3.toString());
    //return strAndPara;
    subQuery.pack();
    return subQuery;
  }

  /**
   * getCompletedProgressIDListSQLByUserRecordID
   * get the subQuery of CompletedProgressID list
   * @param userRecordID
   * @return
   */
  private AbstractQuery getCompletedProgressIDListSQLByUserRecordID(Integer userRecordID){
    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    AbstractQuery subQuery = new SubQuery();
    StringBuffer sqlStat = new StringBuffer();

        sqlStat.append(" SELECT DISTINCT A.WORKFLOW_PROGRESS_ID ");
        sqlStat.append(" FROM  MTM_WF_PROGRESS_USER_RECORD A, ");
        sqlStat.append("       WORKFLOW_PROGRESS B, ");
        sqlStat.append("       WORKFLOW_STEP C, ");
        sqlStat.append("       MTM_WF_STEP_USER_ACTOR D ");
        sqlStat.append(" WHERE A.WORKFLOW_PROGRESS_ID = B.ID ");
        sqlStat.append(" AND   B.WORKFLOW_STEP_ID = C.ID ");
        sqlStat.append(" AND   A.RECORD_STATUS = ? ");
        sqlStat.append(" AND   C.WORKFLOW_RULE = '*' ");
        sqlStat.append(" AND   A.WORKFLOW_ACTION <> ? "); //P
        sqlStat.append(" AND   A.WORKFLOW_ACTION <> ? "); //I
        sqlStat.append(" AND   A.WORKFLOW_ACTION <> ? "); //L
        sqlStat.append(" AND   A.USER_RECORD_ID = ? ");
        sqlStat.append(" AND   D.ACTOR_TYPE = ? "); //D

       // strAndPara.setSqlStr(sqlStat.toString());
        subQuery.append(sqlStat.toString());

        subQuery.setParameter(1, GlobalConstant.RECORD_STATUS_ACTIVE);

        subQuery.setParameter(2, WorkflowProgress.STATUS_PENDING);

        subQuery.setParameter(3, WorkflowProgress.STATUS_IN_PROGRESS);

        subQuery.setParameter(4, WorkflowProgress.STATUS_LOCK);

        subQuery.setParameter(5, userRecordID);

        subQuery.setParameter(6, MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN);

        subQuery.pack();
        return subQuery;
  }

  /**
   * getGeneralSearchSql
   * @param searchForm
   * @return
   * @throws ApplicationException
   */
  private StringBuffer getGeneralSearchSql(AbstractSearchForm searchForm) throws ApplicationException {
    String searchDateFrom;
    String searchDateTo;
    StringBuffer sqlStat = new StringBuffer();
    ListWorkflowProgressForm listForm;
    String docReferenceNumber = "";

    if (!(searchForm instanceof ListWorkflowProgressForm)) {
      return sqlStat;
    }else
    {
      listForm=(ListWorkflowProgressForm)searchForm;
    }
    String trackIDs = "-1";
    if (searchForm instanceof ListWorkflowProgressForm) {
      // get the track ID list by document reference number
      docReferenceNumber = listForm.getDocReferenceNumber();
      if (!Utility.isEmpty(docReferenceNumber)) {
       /* List tmpWfProgressIDList = this.getTrackIDListByDocumentReferenceNumber(listForm.getDocReferenceNumber());
        for (int k = 0; k < tmpWfProgressIDList.size(); k++) {
          trackIDs += "," + (tmpWfProgressIDList.get(k).toString());
        }*/
        trackIDs = this.getTrackIDsByRelatedObject(listForm.getDocReferenceNumber(),GlobalConstant.RECORD_STATUS_ACTIVE);
      }

    }

    ListWorkflowProgressForm wkprogressForm = (ListWorkflowProgressForm) searchForm;
    // search by the arrival or due date
    if ((!Utility.isEmpty(wkprogressForm.getDateFrom())) || (!Utility.isEmpty(wkprogressForm.getDateTo()))) {
      String searchField = "";
      if (WorkflowProgress.SEARCH_ARRIVAL_DATE.equals(wkprogressForm.getDateSearchField())) {
        searchField = "WP.CREATE_DATE";
        searchDateFrom = wkprogressForm.getDateFrom();
        searchDateTo = wkprogressForm.getDateTo();
        sqlStat.append(" AND ");

        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }

        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }
      } else if (WorkflowProgress.SEARCH_DUE_DATE.equals(wkprogressForm.getDateSearchField())) {
        sqlStat.append(" AND  (");
        searchField = "WS.ON_NO_RESPONSE_AFTER";
        searchDateFrom = wkprogressForm.getDateFrom();
        searchDateTo = wkprogressForm.getDateTo();
        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }
        sqlStat.append(" OR ");
        // searchField ="DATE_ADD(WP.CREATE_DATE, WS.ON_NO_RESPONSE_FOR)";
        switch (DataSourceFactory.getDatabaseType()) {
        case DataSourceFactory.DB_MYSQL:
          searchField = "DATE_ADD(WP.CREATE_DATE, INTERVAL WS.ON_NO_RESPONSE_FOR DAY)";
          break;
        case DataSourceFactory.DB_ORACLE:
          searchField = "(WP.CREATE_DATE +  WS.ON_NO_RESPONSE_FOR)";
          break;
        case DataSourceFactory.DB_MSSQL:
          searchField = "DATEADD('d',WS.ON_NO_RESPONSE,WP.CREATE_DATE)";
          break;
        }

        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }
        sqlStat.append(" OR ");
        searchField = "WP.DUE_DATE";
        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            sqlStat.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }

        sqlStat.append(" ) ");
      }

    }
    // search by who send the workflow
    if (!Utility.isEmpty(wkprogressForm.getFromWhom()) && !wkprogressForm.getFromWhom().equals("-1")) {
      sqlStat.append(" AND ");
      sqlStat.append("WP.CREATOR_ID = " + wkprogressForm.getFromWhom());
    }

    // search by the priority of the workflow
    if (!Utility.isEmpty(wkprogressForm.getPriority())) {
      sqlStat.append(" AND ");
      sqlStat.append("WP.PROGRESS_PRIORITY = '" + wkprogressForm.getPriority() + "'");
    }

    // search by the document reference number
    if (!Utility.isEmpty(docReferenceNumber)) {
      sqlStat.append("        AND " + getInSQL("WP.ID", trackIDs) + " \n");
    }
    return sqlStat;
  }


  /**
   * getGeneralSearchSqlStr
   * get the subQuery of the method getGeneralSearchSql
   * @param searchForm
   * @return
   */
  private AbstractQuery getGeneralSearchSqlStr(AbstractSearchForm searchForm){

    String searchDateFrom;
    String searchDateTo;

    ListWorkflowProgressForm listForm;
    String referenceNumber = "";
    String docReferenceNumber = "";


    AbstractQuery subQuery = new SubQuery();

    if (!(searchForm instanceof ListWorkflowProgressForm)) {
      //strAndPara.setSqlStr("");
      //return strAndPara;//MYBE Throws a exception--
      subQuery.append("");
      return subQuery;
    }else
    {
      listForm=(ListWorkflowProgressForm)searchForm;
    }

    if (searchForm instanceof ListWorkflowProgressForm) {
      referenceNumber = listForm.getReferenceNumber();
      docReferenceNumber = listForm.getDocReferenceNumber();
    }

    ListWorkflowProgressForm wkprogressForm = (ListWorkflowProgressForm) searchForm;
    // search by the arrival or due date
    if ((!Utility.isEmpty(wkprogressForm.getDateFrom())) || (!Utility.isEmpty(wkprogressForm.getDateTo()))) {
      String searchField = "";
      if (WorkflowProgress.SEARCH_ARRIVAL_DATE.equals(wkprogressForm.getDateSearchField())) {
        searchField = "WP.CREATE_DATE";
        searchDateFrom = wkprogressForm.getDateFrom();
        searchDateTo = wkprogressForm.getDateTo();
        subQuery.append(" AND ");

        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }

        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }
      } else if (WorkflowProgress.SEARCH_DUE_DATE.equals(wkprogressForm.getDateSearchField())) {
        subQuery.append(" AND  (");
        searchField = "WS.ON_NO_RESPONSE_AFTER";
        searchDateFrom = wkprogressForm.getDateFrom();
        searchDateTo = wkprogressForm.getDateTo();
        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }
        subQuery.append(" OR ");
        // searchField ="DATE_ADD(WP.CREATE_DATE, WS.ON_NO_RESPONSE_FOR)";
        switch (DataSourceFactory.getDatabaseType()) {
        case DataSourceFactory.DB_MYSQL:
          searchField = "DATE_ADD(WP.CREATE_DATE, INTERVAL WS.ON_NO_RESPONSE_FOR DAY)";
          break;
        case DataSourceFactory.DB_ORACLE:
          searchField = "(WP.CREATE_DATE +  WS.ON_NO_RESPONSE_FOR)";
          break;
        case DataSourceFactory.DB_MSSQL:
          searchField = "DATEADD('d',WS.ON_NO_RESPONSE,WP.CREATE_DATE)";
          break;
        }

        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }
        subQuery.append(" OR ");
        searchField = "WP.DUE_DATE";
        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
              + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
          }
        } else {
          if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
          } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
            subQuery.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
          }
        }

        subQuery.append(" ) ");
      }

    }
    // search by who send the workflow
    if (!Utility.isEmpty(wkprogressForm.getFromWhom()) && !wkprogressForm.getFromWhom().equals("-1")) {
      subQuery.append(" AND ");
      subQuery.append("WP.CREATOR_ID = " + wkprogressForm.getFromWhom());
    }

    // search by the priority of the workflow
    if (!Utility.isEmpty(wkprogressForm.getPriority())) {
      subQuery.append(" AND ");
      subQuery.append("WP.PROGRESS_PRIORITY = '" + wkprogressForm.getPriority() + "'");
    }

    if (!Utility.isEmpty(referenceNumber)) {
      subQuery.append("        AND WP.ID IN (").subQuery(this.getTrackIDsSQLByRelatedObject(listForm.getReferenceNumber(),GlobalConstant.RECORD_STATUS_ACTIVE)).append(" ) \n");
    }

    // search by the document reference number
    else if (!Utility.isEmpty(docReferenceNumber)) {
      /* Commented by Brook.Huang. It should just related to DMS object while docReferenceNumber is not empty?
       * subQuery.append("        AND WP.ID IN (").subQuery(this.getTrackIDsSQLByRelatedObject(listForm.getDocReferenceNumber(),GlobalConstant.RECORD_STATUS_ACTIVE)).append(" ) \n");
       */
      subQuery.append("        AND WP.ID IN (").subQuery(this.getTrackIDsSQLByRelatedDMSObject(listForm.getDocReferenceNumber(),GlobalConstant.RECORD_STATUS_ACTIVE)).append(" ) \n");
    }

    subQuery.pack();
    return subQuery;
  }

  public StringBuffer getPendUserSql(AbstractSearchForm searchForm, boolean bFullList, UserRecord userRecord) throws Exception {
    StringBuffer sqlStat = new StringBuffer();

    Integer userRecordID = getEffectiveUserRecordID(searchForm);

    sqlStat.append(getMainQuerySql());

    sqlStat.append(getStatusSql(bFullList));

    sqlStat.append(getSpactActorProgress(userRecord));

    sqlStat.append(getRoleAndGroupSql(searchForm));

    sqlStat.append(getNotInvolveProgressSql(searchForm));

    sqlStat.append(getNotOutstandProgressSql(bFullList, userRecordID));

    sqlStat.append(getSearchableSql(searchForm));

    sqlStat.append(getPermissionSql());

    sqlStat.append(getGeneralSearchSql(searchForm));

    return sqlStat;
  }

  /**
   * getPendUserSqlStr
   * get the subQuery of method getPendUserSql
   * @param searchForm
   * @param bFullList
   * @param userRecord
   * @return
   * @throws SQLException
   * @throws Exception
   */
  public AbstractQuery getPendUserSqlStr(AbstractSearchForm searchForm, boolean bFullList, UserRecord userRecord) throws SQLException, Exception{
   // StringBuffer sqlStat = new StringBuffer();
   // SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    AbstractQuery subQuery = new SubQuery();
    boolean isIncludeDelegateUser = false;
    if(searchForm instanceof ListWorkflowProgressForm){
      isIncludeDelegateUser = ((ListWorkflowProgressForm)searchForm).isIncludeDelegateReocrd();
    }
    Integer userRecordID = getEffectiveUserRecordID(searchForm);
    //sqlStat.append(getMainQuerySql());
   // SqlstrAndParameters tmpStrPara0 = getMainQuerySqlStr();
    //sqlStat.append(tmpStrPara0.getSqlStr());
    //strAndPara.addAllParameters(tmpStrPara0.getParameters());
    subQuery.subQuery(getMainQuerySqlStr(searchForm));
    //log.debug(QueryUtil.checkPara(getMainQuerySqlStr()));


    //sqlStat.append(getStatusSql(bFullList));
    //SqlstrAndParameters tmpStrPara1 = getStatusSqlStr(bFullList,userRecord.getID());
    //sqlStat.append(tmpStrPara1.getSqlStr());
    //strAndPara.addAllParameters(tmpStrPara1.getParameters());
    subQuery.subQuery(getStatusSqlStr(bFullList,userRecord.getID(),isIncludeDelegateUser));
    //log.debug(QueryUtil.checkPara(getStatusSqlStr(bFullList,userRecord.getID())));


    //sqlStat.append(getSpactActorProgress(userRecord));
    //SqlstrAndParameters tmpStrPara2 = getSpactActorProgressSQL(userRecord);
    //sqlStat.append(tmpStrPara2.getSqlStr());
    //strAndPara.addAllParameters(tmpStrPara2.getParameters());
    subQuery.subQuery(getSpactActorProgressSQL(userRecord));
    //log.debug(QueryUtil.checkPara(getSpactActorProgressSQL(userRecord)));

   // sqlStat.append(getRoleAndGroupSql(searchForm));
   // SqlstrAndParameters tmpStrPara3 = getRoleAndGroupSqlStr(searchForm);
   // sqlStat.append(tmpStrPara3.getSqlStr());
   // strAndPara.addAllParameters(tmpStrPara3.getParameters());
    subQuery.subQuery(getRoleAndGroupSqlStr(searchForm));
    //log.debug(QueryUtil.checkPara(getRoleAndGroupSqlStr(searchForm)));


    //sqlStat.append(getNotInvolveProgressSql(searchForm));
    subQuery.subQuery(getNotInvolveProgressSqlStr(searchForm));
    //sqlStat.append(getNotOutstandProgressSql(bFullList, userRecordID));


    //SqlstrAndParameters tmpStrPara5 = getNotOutstandProgressSqlStr(bFullList, userRecordID);
    //sqlStat.append(tmpStrPara5.getSqlStr());
    //strAndPara.addAllParameters(tmpStrPara5.getParameters());
    subQuery.subQuery(getNotOutstandProgressSqlStr(bFullList, userRecordID));
    //log.debug(QueryUtil.checkPara(getNotOutstandProgressSqlStr(bFullList, userRecordID)));


    //sqlStat.append(getSearchableSql(searchForm));
    //SqlstrAndParameters tmpStrPara6 = getSearchableSqlStr(searchForm);
    //sqlStat.append(tmpStrPara6.getSqlStr());
    //strAndPara.addAllParameters(tmpStrPara6.getParameters());
    subQuery.subQuery(getSearchableSqlStr(searchForm));
    //log.debug(QueryUtil.checkPara(getSearchableSqlStr(searchForm)));

    //sqlStat.append(getPermissionSql());
    //SqlstrAndParameters tmpStrPara7 = getPermissionSqlStr();
    //sqlStat.append(tmpStrPara7.getSqlStr());
    //strAndPara.addAllParameters(tmpStrPara7.getParameters());
    subQuery.subQuery(getPermissionSqlStr());
    //log.debug(QueryUtil.checkPara(getPermissionSqlStr()));


   // sqlStat.append(getGeneralSearchSql(searchForm));
    //SqlstrAndParameters tmpStrPara8 = getGeneralSearchSqlStr(searchForm);
    //sqlStat.append(tmpStrPara8.getSqlStr());
    //strAndPara.addAllParameters(tmpStrPara8.getParameters());
    subQuery.subQuery(getGeneralSearchSqlStr(searchForm));
    //log.debug(QueryUtil.checkPara(getGeneralSearchSqlStr(searchForm)));


    // strAndPara.setSqlStr(sqlStat.toString());
   // return strAndPara;


    subQuery.pack();

    return subQuery;
  }

  /**
   * getEffectiveUserRoles
   * @param searchForm
   * @return
   * @throws ApplicationException
   */
  private List getEffectiveUserRoles(AbstractSearchForm searchForm) throws ApplicationException {
    if (searchForm instanceof ListWorkflowProgressForm ){
      ListWorkflowProgressForm listForm = (ListWorkflowProgressForm)searchForm;
      if (!Utility.isEmpty(listForm.getDelegateUserRecordID())) {
        Integer userRecordID = TextUtility.parseIntegerObj(listForm.getDelegateUserRecordID());

        UserGroupDAObject groupDAO = new UserGroupDAObject(sessionContainer, dbConn);
        List userGroupsList = groupDAO.getListByUserRecordIDGroupType(userRecordID, UserGroup.GROUP_TYPE_PUBLIC);

        UserRoleDAObject roleDAO = new UserRoleDAObject(sessionContainer, dbConn);
        List userRolesList = roleDAO.getListByUserRecordID(userRecordID);

        for (int i=0; i<userGroupsList.size(); i++) {
          UserGroup userGroup = (UserGroup) userGroupsList.get(i);
          List userRolesByGroup = roleDAO.getListByUserGroupID(userGroup.getID());
          for (int j = 0; j < userRolesByGroup.size(); j++) {
            if (!userRolesList.contains(userRolesByGroup.get(j))) {
              userRolesList.add(userRolesByGroup.get(j));
            }
          }
        }
        return userRolesList;
      }else{
        PermissionManager pm = sessionContainer.getPermissionManager();
        return pm.getUserRoles();
      }
    }else{
      PermissionManager pm = sessionContainer.getPermissionManager();
      return pm.getUserRoles();
    }
  }

/**
 *getEffectiveUserRolesStr
 * get the subQuery of the method getEffectiveUserRoles
 * @param searchForm
 * @return
 *
 */
  private AbstractQuery getEffectiveUserRolesStr(AbstractSearchForm searchForm){

    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    //StringBuffer sqlStat = new StringBuffer();

    AbstractQuery subQuery = new SubQuery();

    if (searchForm instanceof ListWorkflowProgressForm ){
      ListWorkflowProgressForm listForm = (ListWorkflowProgressForm)searchForm;
      if (!Utility.isEmpty(listForm.getDelegateUserRecordID())) {
        Integer userRecordID = TextUtility.parseIntegerObj(listForm.getDelegateUserRecordID());

        UserGroupDAObject groupDAO = new UserGroupDAObject(sessionContainer, dbConn);
        UserRoleDAObject roleDAO = new UserRoleDAObject(sessionContainer, dbConn);
        AbstractQuery userRoles = roleDAO.getListSQLByUserRecordID(userRecordID);
        AbstractQuery userRolesByGroup = getUserRoleIDsSQLByUserGroupIDs(groupDAO.getListSQLByUserRecordIDGroupType(userRecordID,UserGroup.GROUP_TYPE_PUBLIC));

        //sqlStat.append(strAndParauserRoles.getSqlStr());
        subQuery.subQuery(userRoles);
        subQuery.append(" \tUNION\t ");
        subQuery.subQuery(userRolesByGroup);
        //strAndPara.setSqlStr(sqlStat.toString());
        //strAndPara.addAllParameters(strAndParauserRoles.getParameters());
        //strAndPara.addAllParameters(strAndParauserRolesByGroup.getParameters());
        //return strAndPara;
        subQuery.pack();
        return subQuery;
      }else{
        PermissionManager pm = sessionContainer.getPermissionManager();
        //sqlStat.append(formatListToSQLString("com.dcivision.user.bean.UserRole",pm.getUserRoles()));
        //strAndPara.setSqlStr(sqlStat.toString());
        //return strAndPara;

        subQuery.append(formatListToSQLString(UserRole.class.getName(),pm.getUserRoles()));//"com.dcivision.user.bean.UserRole"
        subQuery.pack();
        return subQuery;
      }
    }else{
      PermissionManager pm = sessionContainer.getPermissionManager();
      //sqlStat.append(formatListToSQLString("com.dcivision.user.bean.UserRole",pm.getUserRoles()));
      //strAndPara.setSqlStr(sqlStat.toString());
      //return strAndPara;
      subQuery.append(formatListToSQLString(UserRole.class.getName(),pm.getUserRoles()));//"com.dcivision.user.bean.UserRole"
      subQuery.pack();
      return subQuery;
    }

  }

 private AbstractQuery getEffectiveDelegateUserRolesStr(AbstractSearchForm searchForm) throws ApplicationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException{
   AbstractQuery subQuery = new SubQuery();
   UserGroupDAObject groupDAO = new UserGroupDAObject(sessionContainer, dbConn);
   UserRoleDAObject roleDAO = new UserRoleDAObject(sessionContainer, dbConn);
   UserDelegationDAObject delegateDAO = new UserDelegationDAObject(this.sessionContainer,this.dbConn);
   List delegateUserList = delegateDAO.getListDelegatedToUser();
   if(!Utility.isEmpty(delegateUserList)){
     List sourceUserIDs = Utility.getPropertyList(delegateUserList, "sourceUserID");

     AbstractQuery userRoles = roleDAO.getListSQLByUserRecordIDs(sourceUserIDs);
     AbstractQuery userRolesByGroup = getUserRoleIDsSQLByUserGroupIDs(groupDAO.getListSQLByUserRecordIDsGroupType(sourceUserIDs,UserGroup.GROUP_TYPE_PUBLIC));

     subQuery.subQuery(userRoles);
     subQuery.append(" \tUNION\t ");
     subQuery.subQuery(userRolesByGroup);
     subQuery.pack();
   }
   return subQuery;
 }
  /**
   * getUserRoleIDsSQLByUserGroupIDs
   * get the subQuery of UserRole's ID list by UserGroup IDs
   * @param userGroupIDs
   * @return AbstractQuery
   */
  private AbstractQuery getUserRoleIDsSQLByUserGroupIDs(AbstractQuery userGroupIDs){
    AbstractQuery subQuery = new SubQuery();
    subQuery.append("SELECT A.ID  ");
    subQuery.append("FROM   USER_ROLE A, MTM_USER_GROUP_USER_ROLE B ");
    subQuery.append("WHERE  A.RECORD_STATUS = ? AND B.USER_GROUP_ID IN (").subQuery(userGroupIDs).append(" ) AND A.ID = B.USER_ROLE_ID ");//B.USER_GROUP_ID = ?

    subQuery.setParameter(1, GlobalConstant.RECORD_STATUS_ACTIVE);
    subQuery.pack();
    return subQuery;
  }

  //TC ADD END

  private List getEffectiveUserGroups(AbstractSearchForm searchForm) throws ApplicationException {
    if (searchForm instanceof ListWorkflowProgressForm) {
      ListWorkflowProgressForm listForm = (ListWorkflowProgressForm)searchForm;
      if ( !Utility.isEmpty(listForm.getDelegateUserRecordID())) {
        Integer userRecordID = TextUtility.parseIntegerObj(listForm.getDelegateUserRecordID());

        UserGroupDAObject groupDAO = new UserGroupDAObject(sessionContainer, dbConn);
        List userGroupsList = groupDAO.getListByUserRecordIDGroupType(userRecordID, UserGroup.GROUP_TYPE_PUBLIC);

        return userGroupsList;
      }else{
        PermissionManager pm = sessionContainer.getPermissionManager();
        return pm.getUserGroups();
      }
    }else{
      PermissionManager pm = sessionContainer.getPermissionManager();
      return pm.getUserGroups();
    }
  }

  //ADD BY TC FOR TEST
  private AbstractQuery getEffectiveUserGroupsStr(AbstractSearchForm searchForm){
    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    //StringBuffer sqlStat = new StringBuffer();
    AbstractQuery subQuery = new SubQuery();

    if (searchForm instanceof ListWorkflowProgressForm) {
      ListWorkflowProgressForm listForm = (ListWorkflowProgressForm)searchForm;
      if ( !Utility.isEmpty(listForm.getDelegateUserRecordID())) {
        Integer userRecordID = TextUtility.parseIntegerObj(listForm.getDelegateUserRecordID());
        UserGroupDAObject groupDAO = new UserGroupDAObject(sessionContainer, dbConn);
        subQuery.subQuery(groupDAO.getListSQLByUserRecordIDGroupType(userRecordID, UserGroup.GROUP_TYPE_PUBLIC));
        subQuery.pack();
        return subQuery;
      }else{
        PermissionManager pm = sessionContainer.getPermissionManager();
        subQuery.append(formatListToSQLString(UserGroup.class.getName(),pm.getUserGroups()));//"com.dcivision.user.bean.UserGroup"
        subQuery.pack();
        return subQuery;
      }
    }else{
      PermissionManager pm = sessionContainer.getPermissionManager();
      //sqlStat.append(formatListToSQLString("com.dcivision.user.bean.UserGroup",pm.getUserGroups()));
      //strAndPara.setSqlStr(sqlStat.toString());
      //return strAndPara;
      subQuery.append(formatListToSQLString(UserGroup.class.getName(),pm.getUserGroups()));//"com.dcivision.user.bean.UserGroup"
      subQuery.pack();
      return subQuery;
    }

  }
  private AbstractQuery getEffectiveDelegateUserGroupsStr(AbstractSearchForm searchForm) throws ApplicationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException{
    AbstractQuery subQuery = new SubQuery();
    UserDelegationDAObject delegateDAO = new UserDelegationDAObject(this.sessionContainer,this.dbConn);
    UserGroupDAObject groupDAO = new UserGroupDAObject(sessionContainer, dbConn);

    List delegateUserList = delegateDAO.getListDelegatedToUser();
    if(!Utility.isEmpty(delegateUserList)){
      subQuery.subQuery(groupDAO.getListSQLByUserRecordIDsGroupType(Utility.getPropertyList(delegateUserList, "sourceUserID"), UserGroup.GROUP_TYPE_PUBLIC));
      subQuery.pack();
    }
    return subQuery;
  }
  //TC END

  private StringBuffer getStatusSql(boolean bFullList) {

    StringBuffer sqlStat=new StringBuffer();
    if (bFullList) {
      sqlStat.append("        WP.STATUS <> ? AND \n");
    } else {
      sqlStat.append("        (WP.STATUS = ? OR \n");
      sqlStat.append("        WP.STATUS = ? OR \n");
      sqlStat.append("        WP.STATUS = ?) AND \n");
      sqlStat.append("        WP.COMPLETE_FLAG = ? AND \n");
      // sqlStat.append(" MWSUA.PERMISSION ='RWM' AND \n");
    }
    sqlStat.append("        MWSUA.ACTION_TYPE = ? AND \n");
    sqlStat.append("        ((MWSUA.ACTOR_TYPE = ? AND MWSUA.ACTOR_ID = ?) \n");

    return sqlStat;
  }

  private AbstractQuery getStatusSqlStr(boolean bFullList,Integer userRecordID,boolean isIncludeDelegateUser){
    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    AbstractQuery subquery = new SubQuery();
    StringBuffer sqlStat=new StringBuffer();
    if (bFullList) {
      sqlStat.append("        WP.STATUS <> ? AND \n");
    } else {
      sqlStat.append("        (WP.STATUS = ? OR \n");
      sqlStat.append("        WP.STATUS = ? OR \n");
      sqlStat.append("        WP.STATUS = ?) AND \n");
      sqlStat.append("        WP.COMPLETE_FLAG = ? AND \n");
      // sqlStat.append(" MWSUA.PERMISSION ='RWM' AND \n");
    }
    sqlStat.append("        MWSUA.ACTION_TYPE = ? AND \n");
    sqlStat.append("        ((MWSUA.ACTOR_TYPE = ? AND MWSUA.ACTOR_ID = ?) \n");

    //add by greatwall for bug814
    boolean hasDelegate = false;
    List delegateUserList =null;
    String delegateUserStr= "";
    UserDelegationDAObject userDelegateDAO = new UserDelegationDAObject(sessionContainer, dbConn);
  if(isIncludeDelegateUser){//add by tc for bug-1439
    try{
      delegateUserList = userDelegateDAO.getListDelegatedToUser();
    }
    catch (ApplicationException e){
      //no delegateuser ,do not to do anything
    }
    hasDelegate=(!Utility.isEmpty(delegateUserList))&&delegateUserList.size()>0;
    if(hasDelegate){
      UserDelegation userDelegatetion ;
      for(int i = 0;i<delegateUserList.size();i++){
        userDelegatetion = (UserDelegation)delegateUserList.get(i);
        if(!Utility.isEmpty(userDelegatetion)){
          delegateUserStr+=userDelegatetion.getSourceUserID().toString();
          if(i<delegateUserList.size()-1){
            delegateUserStr+=",";
          }
        }
      }
      if(!Utility.isEmpty(delegateUserStr)){
        sqlStat.append("  OR  (MWSUA.ACTOR_TYPE = ? AND MWSUA.ACTOR_ID IN("+delegateUserStr+"))\n");
      }
    }
   }//Add by tc end
    /* strAndPara.setSqlStr(sqlStat.toString());
    if (bFullList) {
    strAndPara.addParameters(WorkflowProgress.STATUS_SUBMIT);
    }else{
    strAndPara.addParameters(WorkflowProgress.STATUS_PENDING);
    strAndPara.addParameters(WorkflowProgress.STATUS_LOCK);
    strAndPara.addParameters(WorkflowProgress.STATUS_IN_PROGRESS);
    strAndPara.addParameters(GlobalConstant.FALSE);
    }
    strAndPara.addParameters(MtmWorkflowStepUserActor.ACTION_TYPE_EXECUTION);
    strAndPara.addParameters(MtmWorkflowStepUserActor.ACTOR_TYPE_USER);
    strAndPara.addParameters(userRecordID.toString());
    return strAndPara;*/
    subquery.append(sqlStat.toString());
    int i=1;
    if(bFullList){
      subquery.setParameter(i++, WorkflowProgress.STATUS_SUBMIT);
    }else{
      subquery.setParameter(i++,WorkflowProgress.STATUS_PENDING);
      subquery.setParameter(i++,WorkflowProgress.STATUS_LOCK);
      subquery.setParameter(i++,WorkflowProgress.STATUS_IN_PROGRESS);
      subquery.setParameter(i++,GlobalConstant.FALSE);
    }
    subquery.setParameter(i++,MtmWorkflowStepUserActor.ACTION_TYPE_EXECUTION);
    subquery.setParameter(i++,MtmWorkflowStepUserActor.ACTOR_TYPE_USER);
    subquery.setParameter(i++,userRecordID.toString());
    if(!Utility.isEmpty(delegateUserStr)){
      subquery.setParameter(i++,MtmWorkflowStepUserActor.ACTOR_TYPE_USER);
    }
    return subquery;
  }

  private StringBuffer getRoleAndGroupSql(AbstractSearchForm searchForm) throws ApplicationException {
    StringBuffer sqlStat=new StringBuffer();
    List userRolesList = getEffectiveUserRoles(searchForm);
    List userGroupsList = getEffectiveUserGroups(searchForm);
    String tmpStr = "";
    for (int i = 0; userGroupsList != null && i < userGroupsList.size(); i++) {
      if (i != 0) {
        tmpStr += ", ";
      }
      UserGroup group = (UserGroup) userGroupsList.get(i);
      tmpStr += group.getID();
    }
    if (!Utility.isEmpty(tmpStr)) {
      sqlStat.append("         OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP + "' AND " + getInSQL("MWSUA.ACTOR_ID", tmpStr) + " ) \n");
    }
    tmpStr = "";
    for (int i = 0; userRolesList != null && i < userRolesList.size(); i++) {
      if (i != 0) {
        tmpStr += ", ";
      }
      UserRole role = (UserRole) userRolesList.get(i);
      tmpStr += role.getID();
    }
    if (!Utility.isEmpty(tmpStr)) {
      sqlStat.append("         OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE + "' AND " + getInSQL("MWSUA.ACTOR_ID", tmpStr) + " ) \n");
    }
    sqlStat.append("        ) ");
    return sqlStat;
  }

  //ADD BY TC FOR TEST
  private AbstractQuery getRoleAndGroupSqlStr(AbstractSearchForm searchForm){
    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    //StringBuffer sqlStat=new StringBuffer();

    AbstractQuery subQuery = new SubQuery();
    boolean isIncludeDelegateUserTaskList = false;

    if(searchForm instanceof ListWorkflowProgressForm){
      isIncludeDelegateUserTaskList = ((ListWorkflowProgressForm)searchForm).isIncludeDelegateReocrd();
    }
    //SqlstrAndParameters strAndParauserRole = getEffectiveUserRolesStr(searchForm);
    //SqlstrAndParameters strAndParauserGroup = getEffectiveUserGroupsStr(searchForm);
    AbstractQuery strAndParauserRole  = getEffectiveUserRolesStr(searchForm);
    AbstractQuery strAndParauserGroup = getEffectiveUserGroupsStr(searchForm);
    AbstractQuery strAndParaDelegateUserGroup = null;
    AbstractQuery strAndParaDelegateUserRole = null;
    try{
      if(isIncludeDelegateUserTaskList){//if isIncludeDelegateUserTaskList then do it
        strAndParaDelegateUserGroup=getEffectiveDelegateUserGroupsStr(searchForm);
        strAndParaDelegateUserRole=getEffectiveDelegateUserRolesStr(searchForm);
      }
    }catch(Exception ex){
      strAndParaDelegateUserGroup=null;
      strAndParaDelegateUserRole=null;
      log.error(ex, ex);
    }

    int i=1;
    if(!Utility.isEmpty(strAndParauserGroup.toString())){
    //sqlStat.append("         OR (MWSUA.ACTOR_TYPE = ? AND " + getInSQLStr("MWSUA.ACTOR_ID", strAndParauserGroup.getSqlStr()) + " ) \n");
    //strAndPara.addParameters(MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP);
    //strAndPara.addAllParameters(strAndParauserGroup.getParameters());
      subQuery.append("         OR (MWSUA.ACTOR_TYPE = ? AND MWSUA.ACTOR_ID IN (").subQuery(strAndParauserGroup).append(" ))\n");
      subQuery.setParameter(i++, MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP);
    }
    if(!Utility.isEmpty(strAndParaDelegateUserGroup)&&!Utility.isEmpty(strAndParaDelegateUserGroup.toString())){
      subQuery.append("         OR (MWSUA.ACTOR_TYPE = ? AND MWSUA.ACTOR_ID IN (").subQuery(strAndParaDelegateUserGroup).append(" ))\n");
      subQuery.setParameter(i++, MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP);
    }
    if(!Utility.isEmpty(strAndParauserRole.toString())){
    //sqlStat.append("         OR (MWSUA.ACTOR_TYPE = ? AND " + getInSQLStr("MWSUA.ACTOR_ID", strAndParauserRole.getSqlStr()) + " ) \n");
    //strAndPara.addParameters(MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE);
    //strAndPara.addAllParameters(strAndParauserRole.getParameters());
      subQuery.append("        OR (MWSUA.ACTOR_TYPE = ? AND MWSUA.ACTOR_ID IN (").subQuery(strAndParauserRole).append(" ))\n");
      subQuery.setParameter(i++, MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE);
    }
    if(!Utility.isEmpty(strAndParaDelegateUserRole)&&!Utility.isEmpty(strAndParaDelegateUserRole.toString())){
      subQuery.append("        OR (MWSUA.ACTOR_TYPE = ? AND MWSUA.ACTOR_ID IN (").subQuery(strAndParaDelegateUserRole).append(" ))\n");
      subQuery.setParameter(i++, MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE);
    }
    //sqlStat.append("        ) ");
      subQuery.append(")");
    //strAndPara.setSqlStr(sqlStat.toString());
    //return strAndPara;
    subQuery.pack();
    return subQuery;
  }


  private StringBuffer getPermissionSql() {
    StringBuffer sqlStat=new StringBuffer();
    if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_MYSQL) {
      sqlStat.append("AND  BINARY MWSUA.PERMISSION LIKE  ? ");
    } else {
      sqlStat.append("AND  MWSUA.PERMISSION LIKE  ? ");
    }
    return sqlStat;
  }

  private AbstractQuery getPermissionSqlStr(){
    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    AbstractQuery subQuery = new SubQuery();
    StringBuffer sqlStat=new StringBuffer();
    if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_MYSQL) {
      sqlStat.append("AND  BINARY MWSUA.PERMISSION LIKE  ? ");
    } else {
      sqlStat.append("AND  MWSUA.PERMISSION LIKE  ? ");
    }

    String permissionKeyword = this.getFormattedKeyword(WORKFLOW_PERMISSION_TYPE_READ, "LIKE");
    //strAndPara.setSqlStr(sqlStat.toString());
    //strAndPara.addParameters(permissionKeyword);
    //return strAndPara;
    subQuery.append(sqlStat.toString());
    subQuery.setParameter(1,permissionKeyword);
    subQuery.pack();
    return subQuery;
  }

  private StringBuffer getSearchableSql(AbstractSearchForm searchForm) {
    StringBuffer sqlStat=new StringBuffer();
    if (searchForm.isSearchable()) {
      String searchField = getSearchColumn(searchForm.getBasicSearchField(), "WP");
      sqlStat.append("AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? ");
    }
    return  sqlStat;
  }
//Add BY TC for TEST
  private AbstractQuery getSearchableSqlStr(AbstractSearchForm searchForm){
    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    AbstractQuery subQuery = new SubQuery();

    StringBuffer sqlStat=new StringBuffer();
    if (searchForm.isSearchable()) {
      String searchField = getSearchColumn(searchForm.getBasicSearchField(), "WP");
      sqlStat.append("AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? ");
      String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
      //strAndPara.addParameters(searchKeyword);
      subQuery.setParameter(1,searchKeyword);
    }
    //strAndPara.setSqlStr(sqlStat.toString());
    //return strAndPara;
    subQuery.append(sqlStat.toString());
    subQuery.pack();
    return subQuery;
  }

  private StringBuffer getNotOutstandProgressSql(boolean bFullList,  Integer userRecordID) throws SQLException, Exception {
    StringBuffer sqlStat=new StringBuffer();
    StringBuffer sqlStat2 = new StringBuffer();
    if (!bFullList) {
      sqlStat2.append("SELECT WORKFLOW_PROGRESS_ID ");
      sqlStat2.append("FROM MTM_WF_PROGRESS_USER_RECORD ");
      sqlStat2.append("WHERE USER_RECORD_ID = " + userRecordID.toString());
      sqlStat2.append(" AND WORKFLOW_ACTION <> '" + WorkflowProgress.STATUS_IN_PROGRESS + "' ");
      sqlStat2.append(" AND WORKFLOW_ACTION <> '" + WorkflowProgress.STATUS_PENDING + "' ");

      PreparedStatement preStat2 = null;
      preStat2 = dbConn.prepareStatement(sqlStat2.toString());
      ResultSet rs2 = null;
      rs2 = preStat2.executeQuery();
      String progressID = "";
      while (rs2.next()) {
        progressID += ((progressID.length() > 0) ? "," : "") + getResultSetInteger(rs2, "WORKFLOW_PROGRESS_ID");
      }
      if (!Utility.isEmpty(progressID)) {
        sqlStat.append("           AND " + getNotInSQL("WP.ID", progressID) + " ");
      }
      try {
        rs2.close();
      } catch (Exception ignore) {
      } finally {
        rs2 = null;
      }
      try {
        preStat2.close();
      } catch (Exception ignore) {
      } finally {
        preStat2 = null;
      }
    }
    return sqlStat;
  }


  //ADD By TC for TEST
  private AbstractQuery getNotOutstandProgressSqlStr(boolean bFullList,  Integer userRecordID){
    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    AbstractQuery subQuery = new SubQuery();
    StringBuffer sqlStat=new StringBuffer();
    StringBuffer sqlStat2 = new StringBuffer();
    if (!bFullList) {
      sqlStat2.append("SELECT 'X' ");//WORKFLOW_PROGRESS_ID
      sqlStat2.append("FROM MTM_WF_PROGRESS_USER_RECORD MWPURN ");
      sqlStat2.append("WHERE MWPURN.USER_RECORD_ID = ? ");
      sqlStat2.append(" AND MWPURN.WORKFLOW_ACTION <> ? ");
      sqlStat2.append(" AND MWPURN.WORKFLOW_ACTION <> ? ");
      sqlStat2.append(" AND WP.ID = MWPURN.WORKFLOW_PROGRESS_ID ");
      //sqlStat.append(" AND "+getNotInSQLStr("WP.ID",sqlStat2.toString())+" ");
      sqlStat.append(" AND NOT EXISTS ("+sqlStat2.toString()+") ");
      subQuery.append(sqlStat.toString());
      subQuery.setParameter(1,userRecordID.toString());
      subQuery.setParameter(2,WorkflowProgress.STATUS_IN_PROGRESS);
      subQuery.setParameter(3,WorkflowProgress.STATUS_PENDING);
      //strAndPara.addParameters(userRecordID.toString());
      //strAndPara.addParameters(WorkflowProgress.STATUS_IN_PROGRESS);
      //strAndPara.addParameters(WorkflowProgress.STATUS_PENDING);
    }
    //strAndPara.setSqlStr(sqlStat.toString());
    //return strAndPara;
    subQuery.pack();
    return subQuery;
  }

  private StringBuffer getNotInvolveProgressSql(AbstractSearchForm searchForm) throws ApplicationException {
    StringBuffer sqlStat=new StringBuffer();

    String sNotInvolvedWorkflowProgressIDList = this.formatListToSQLString(this.getNotInvolvedWorkflowProgressIDList(searchForm));
    if (!Utility.isEmpty(sNotInvolvedWorkflowProgressIDList)) {
      sqlStat.append("        AND " + getNotInSQL("WP.ID", sNotInvolvedWorkflowProgressIDList) + " ");
    }

    String sNotInvolvedWorkflowProgressIDListForDynamic = this.formatListToSQLString(this.getNotInvolvedWorkflowProgressIDforDynamic(searchForm));
    if (!Utility.isEmpty(sNotInvolvedWorkflowProgressIDListForDynamic)) {
      sqlStat.append("        AND " + getNotInSQL("WP.ID", sNotInvolvedWorkflowProgressIDListForDynamic) + " ");
    }

    return sqlStat;
  }

  private AbstractQuery getNotInvolveProgressSqlStr(AbstractSearchForm searchForm) throws ApplicationException{
   AbstractQuery subQuery = new SubQuery();
   String sNotInvolvedWorkflowProgressIDList = this.formatListToSQLString(this.getNotInvolvedWorkflowProgressIDList(searchForm));
   if (!Utility.isEmpty(sNotInvolvedWorkflowProgressIDList)) {
     subQuery.append("        AND " + getNotInSQL("WP.ID", sNotInvolvedWorkflowProgressIDList) + " ");
   }
   AbstractQuery sNotInvolvedWorkflowProgressIDListForDynamic = this.getNotInvolvedWorkflowProgressIDforDynamicStr(searchForm);
   subQuery.append("     AND NOT EXISTS (").subQuery(sNotInvolvedWorkflowProgressIDListForDynamic).append(" ) ");
   subQuery.pack();
   return subQuery;
  }


  private StringBuffer getSpactActorProgress(UserRecord userRecord) throws ApplicationException {
    StringBuffer sqlStat=new StringBuffer();
    String sProgressIDListForSubmitter = this.formatListToSQLString(this.getProgressIDListBySubmitterOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER, userRecord.getID()));
    String sProgressIDListForSubmitterReportTo = this.formatListToSQLString(this.getProgressIDListBySubmitterOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO, userRecord.getID()));

    // Temporarily not supported
    // String sTrackIDListForPreviousTaskOwner =
    // this.formatListToSQLString(this.getTrackIDListForPreviousTaskOwner(userRecord.getID()));

    String sProgressIDListForPreviousTaskActorTaker = this.formatListToSQLString(this.getProgressIDListByPreviousActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER, userRecord.getID()));
    String sProgressIDListForReportToOfPreviousTask = this.formatListToSQLString(this.getProgressIDListByPreviousActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER, userRecord.getUserLinkID()));

    String sProgressIDListForActionTaker = this.formatListToSQLString(this.getProgressIDListByStepActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER, userRecord.getID()));
    String sProgressIDListForActionTakerReportTo = this.formatListToSQLString(this.getProgressIDListByStepActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER, userRecord.getID()));

    sqlStat.append("          OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE + "') \n");

    if (!Utility.isEmpty(sProgressIDListForSubmitter)) {
      sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER + "' AND " + getInSQL("WP.ID", sProgressIDListForSubmitter) + " ) \n");
    }
    if (!Utility.isEmpty(sProgressIDListForSubmitterReportTo)) {
      sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO + "' AND " + getInSQL("WP.ID", sProgressIDListForSubmitterReportTo) + " ) \n");
    }
    // if (!Utility.isEmpty(sTrackIDListForPreviousTaskOwner)) {
    // sqlStat.append(" OR (MWSUA.ACTOR_TYPE = '" +
    // MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_OWNER + "' AND " +
    // getInSQL("WP.TRACK_ID", sTrackIDListForPreviousTaskOwner) + " ) \n");
    // }
    if (!Utility.isEmpty(sProgressIDListForActionTaker)) {
      sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER + "' AND " + getInSQL("WP.ID", sProgressIDListForActionTaker) + " ) \n");
    }
    if (!Utility.isEmpty(sProgressIDListForActionTakerReportTo)) {
      sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER + "' AND " + getInSQL("WP.ID", sProgressIDListForActionTakerReportTo)
        + " ) \n");
    }
    if (!Utility.isEmpty(sProgressIDListForPreviousTaskActorTaker)) {
      sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER + "' AND " + getInSQL("WP.ID", sProgressIDListForPreviousTaskActorTaker)
        + " ) \n");
    }
    if (!Utility.isEmpty(sProgressIDListForReportToOfPreviousTask)) {
      sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER + "' AND "
        + getInSQL("WP.ID", sProgressIDListForReportToOfPreviousTask) + " ) \n");
    }
    return sqlStat;
  }

  private AbstractQuery getSpactActorProgressSQL(UserRecord userRecord) throws ApplicationException{
    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    AbstractQuery subQuery = new SubQuery();
   // StringBuffer sqlStat=new StringBuffer();


    //SqlstrAndParameters tmpStrPara = this.getProgressIDListSQLBySubmitterOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER, userRecord.getID());
    //String sProgressIDListForSubmitter = tmpStrPara.getSqlStr();
    AbstractQuery sProgressIDListForSubmitter = this.getProgressIDListSQLBySubmitterOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER, userRecord.getID());

    //SqlstrAndParameters tmpStrParaReportTo = this.getProgressIDListSQLBySubmitterOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO, userRecord.getID());
    //String sProgressIDListForSubmitterReportTo = tmpStrParaReportTo.getSqlStr();
    AbstractQuery sProgressIDListForSubmitterReportTo = this.getProgressIDListSQLBySubmitterOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO, userRecord.getID());


    //SqlstrAndParameters tmpStrParaPreviousActorTaker = this.getProgressIDListSQLByPreviousActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER, userRecord.getID());
    //String sProgressIDListForPreviousTaskActorTaker = tmpStrParaPreviousActorTaker.getSqlStr();
    AbstractQuery sProgressIDListForPreviousTaskActorTaker = this.getProgressIDListSQLByPreviousActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER, userRecord.getID());


    //SqlstrAndParameters tmpStrParaPreviousTask = this.getProgressIDListSQLByPreviousActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER, userRecord.getUserLinkID());
    //String sProgressIDListForReportToOfPreviousTask = tmpStrParaPreviousTask.getSqlStr();
   // AbstractQuery sProgressIDListForReportToOfPreviousTask = this.getProgressIDListSQLByPreviousActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER, userRecord.getUserLinkID());   // falcon_delete EIP-238
    AbstractQuery sProgressIDListForReportToOfPreviousTask = this.getProgressIDListSQLByPreviousActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER, userRecord.getID());   // falcon_add EIP-238

    //SqlstrAndParameters tmpStrParaActionTaker = this.getProgressIDListSQLByStepActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER, userRecord.getID());
    //String sProgressIDListForActionTaker = tmpStrParaActionTaker.getSqlStr();
    AbstractQuery sProgressIDListForActionTaker = this.getProgressIDListSQLByStepActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER, userRecord.getID());


    //SqlstrAndParameters tmpStrParaActionTakerReportTo = this.getProgressIDListSQLByStepActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER, userRecord.getID());
    //String sProgressIDListForActionTakerReportTo = tmpStrParaActionTakerReportTo.getSqlStr();
    AbstractQuery sProgressIDListForActionTakerReportTo = this.getProgressIDListSQLByStepActionTakerOrReportTo(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER, userRecord.getID());


    //sqlStat.append("          OR MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE + "' \n");
    subQuery.append("          OR MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE + "' \n");
    if (!Utility.isEmpty(sProgressIDListForSubmitter)) {
      //sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER + "' AND " + getInSQLStr("WP.ID", sProgressIDListForSubmitter) + " ) \n");
      //strAndPara.addAllParameters(tmpStrPara.getParameters());
      //subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER + "' AND WP.ID IN (").subQuery(sProgressIDListForSubmitter).append(" )) \n");
      subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER + "' AND EXISTS (").subQuery(sProgressIDListForSubmitter).append(" )) \n");
    }
    if (!Utility.isEmpty(sProgressIDListForSubmitterReportTo)) {
      //sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO + "' AND " + getInSQLStr("WP.ID", sProgressIDListForSubmitterReportTo) + " ) \n");
      //strAndPara.addAllParameters(tmpStrParaReportTo.getParameters());
      //subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO + "' AND WP.ID IN (").subQuery(sProgressIDListForSubmitterReportTo).append(" )) \n");
      subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO + "' AND EXISTS (").subQuery(sProgressIDListForSubmitterReportTo).append(" )) \n");
    }

    if (!Utility.isEmpty(sProgressIDListForActionTaker)) {
      //sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER + "' AND " + getInSQLStr("WP.ID", sProgressIDListForActionTaker) + " ) \n");
      //strAndPara.addAllParameters(tmpStrParaActionTaker.getParameters());
      //subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER + "' AND WP.ID IN (").subQuery(sProgressIDListForActionTaker).append(" )) \n");
      subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER + "' AND EXISTS (").subQuery(sProgressIDListForActionTaker).append(" )) \n");
    }
    if (!Utility.isEmpty(sProgressIDListForActionTakerReportTo)) {
      //sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER + "' AND " + getInSQLStr("WP.ID", sProgressIDListForActionTakerReportTo)
      //  + " ) \n");
     // strAndPara.addAllParameters(tmpStrParaActionTakerReportTo.getParameters());
      //subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER + "' AND WP.ID IN (").subQuery(sProgressIDListForActionTakerReportTo).append(" )) \n");
      subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER + "' AND EXISTS (").subQuery(sProgressIDListForActionTakerReportTo).append(" )) \n");
    }
    if (!Utility.isEmpty(sProgressIDListForPreviousTaskActorTaker)) {
      //sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER + "' AND " + getInSQLStr("WP.ID", sProgressIDListForPreviousTaskActorTaker)
      //  + " ) \n");
      //strAndPara.addAllParameters(tmpStrParaPreviousActorTaker.getParameters());
      //subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER + "' AND WP.ID IN (").subQuery(sProgressIDListForPreviousTaskActorTaker).append(" )) \n");
      subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER + "' AND EXISTS (").subQuery(sProgressIDListForPreviousTaskActorTaker).append(" )) \n");
    }
    if (!Utility.isEmpty(sProgressIDListForReportToOfPreviousTask)) {
      //sqlStat.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER + "' AND "
      //  + getInSQLStr("WP.ID", sProgressIDListForReportToOfPreviousTask) + " ) \n");
     // strAndPara.addAllParameters(tmpStrParaPreviousTask.getParameters());
     //subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER + "' AND WP.ID IN (").subQuery(sProgressIDListForReportToOfPreviousTask).append(")) \n");
     subQuery.append("             OR (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER + "' AND EXISTS (").subQuery(sProgressIDListForReportToOfPreviousTask).append(")) \n");
    }


    //strAndPara.setSqlStr(sqlStat.toString());
    //return strAndPara;
    subQuery.pack();
    return subQuery;
  }

  private StringBuffer getMainQuerySql() {
    StringBuffer sqlStat=new StringBuffer();
    sqlStat.append("SELECT  DISTINCT WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.SEQ_NO, WP.STATUS, WP.POST_PROGRESS, WP.DUE_DATE, WP.NEXT_STEP_DUE_DATES, WP.PROGRESS_PRIORITY, WP.USER_DEF_1, WP.USER_DEF_2, WP.USER_DEF_3, WP.USER_DEF_4, WP.USER_DEF_5, WP.RECORD_STATUS, WP.UPDATE_COUNT, WP.CREATOR_ID, WP.CREATE_DATE, WP.UPDATER_ID, WP.UPDATE_DATE AS UPDATE_DATE, WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR, WSTAGE.STAGE_NAME  \n");
    sqlStat.append("FROM    WORKFLOW_STEP WS LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON WS.ID=SS.WORKFLOW_STEP_ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON  SS.WORKFLOW_STAGE_ID=WSTAGE.ID, WORKFLOW_PROGRESS WP, MTM_WF_STEP_USER_ACTOR MWSUA, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC \n");
    sqlStat.append("WHERE   WR.ID = WS.WORKFLOW_RECORD_ID AND \n");
    sqlStat.append("        WR.WORKFLOW_CATEGORY_ID = SOWC.ID AND \n");
    sqlStat.append("        WS.ID = WP.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WS.ID = MWSUA.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WR.RECORD_STATUS = ? AND \n");
    sqlStat.append("        MWSUA.RECORD_STATUS = ? AND \n");
    // sqlStat.append(" MWSUA.PERMISSION = 'W' AND \n");
    sqlStat.append("        WP.CANCEL_FLAG = ? AND \n");
    sqlStat.append("        WS.ACTION_TYPE <> ? AND \n");
    sqlStat.append("        MWSUA.ACTOR_TYPE <> ? AND \n");
    sqlStat.append("        WS.STEP_SEQ <> " + WorkflowStep.END_STEP_SEQ_NO + "  AND \n");
    return sqlStat;
  }

  private AbstractQuery getMainQuerySqlStr(AbstractSearchForm searchForm){
  //------bill add for EIP-1175 start
  boolean isSearchByCategory=false;  //Is search by category
  boolean isSearchFieldNull=Utility.isEmpty(searchForm.getBasicSearchField());   //Is searchForm null
  if(!isSearchFieldNull){
    String basicSearchField=searchForm.getBasicSearchField();
    isSearchByCategory=basicSearchField.equals("SOWC.WORKFLOW_CATEGORY_NAME");
  }
  //------bill add for EIP-1175 end

    AbstractQuery subQuery = new SubQuery();
    StringBuffer sqlStat=new StringBuffer();//DISTINCT//WP.USER_DEF_1, WP.USER_DEF_2, WP.USER_DEF_3, WP.USER_DEF_4, WP.USER_DEF_5,WP.UPDATE_COUNT, WP.UPDATER_ID, WP.UPDATE_DATE AS UPDATE_DATE,WR.DESCRIPTION AS WORKFLOW_DESCRIPTION,WS.DESCRIPTION AS STEP_DESCRIPTION,SOWC.WORKFLOW_CATEGORY_NAME,
    sqlStat.append("SELECT  WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.SEQ_NO, WP.STATUS, WP.POST_PROGRESS, WP.DUE_DATE,  WP.UPDATE_DATE AS UPDATE_DATE, WP.NEXT_STEP_DUE_DATES, WP.PROGRESS_PRIORITY,  WP.RECORD_STATUS,  WP.CREATOR_ID, WP.CREATE_DATE, WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE,   WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE,  WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR, WSTAGE.STAGE_NAME \n");
    //------bill add for EIP-1175 start
    if(isSearchByCategory){
      //Search by category
      sqlStat.append("FROM    WORKFLOW_STEP WS LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON SS.WORKFLOW_STEP_ID = WS.ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON WSTAGE.ID = SS.WORKFLOW_STAGE_ID, WORKFLOW_PROGRESS WP, MTM_WF_STEP_USER_ACTOR MWSUA, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC\n");//, SETUP_OPTION_WORKFLOW_CATEGORY SOWC
    }else{
      sqlStat.append("FROM    WORKFLOW_STEP WS LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON SS.WORKFLOW_STEP_ID = WS.ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON WSTAGE.ID = SS.WORKFLOW_STAGE_ID, WORKFLOW_PROGRESS WP, MTM_WF_STEP_USER_ACTOR MWSUA, WORKFLOW_RECORD WR\n");//, SETUP_OPTION_WORKFLOW_CATEGORY SOWC
    }
    //------bill add for EIP-1175 end
    //delete sqlStat.append("FROM    WORKFLOW_PROGRESS WP, MTM_WF_STEP_USER_ACTOR MWSUA, WORKFLOW_RECORD WR , WORKFLOW_STEP WS LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON WS.ID=SS.WORKFLOW_STEP_ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON  SS.WORKFLOW_STAGE_ID=WSTAGE.ID \n");
    sqlStat.append("WHERE   WR.ID = WS.WORKFLOW_RECORD_ID AND \n");
    //------bill add for EIP-1175 start
    if(isSearchByCategory){
      //Search by category
      sqlStat.append("        WR.WORKFLOW_CATEGORY_ID = SOWC.ID AND \n");
    }
    //------bill add for EIP-1175 end
    //delete sqlStat.append("        WR.WORKFLOW_CATEGORY_ID = SOWC.ID AND \n");//
    sqlStat.append("        WS.ID = WP.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WS.ID = MWSUA.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WR.RECORD_STATUS = ? AND \n");
    sqlStat.append("        MWSUA.RECORD_STATUS = ? AND \n");
    //delete sqlStat.append(" MWSUA.PERMISSION = 'W' AND \n");
    sqlStat.append("        WP.CANCEL_FLAG = ? AND \n");
    sqlStat.append("        WS.ACTION_TYPE <> ? AND \n");
    sqlStat.append("        MWSUA.ACTOR_TYPE <> ? AND \n");
    sqlStat.append("        WS.STEP_SEQ <> ?  AND \n");
    subQuery.append(sqlStat.toString());
    int i = 1;
    subQuery.setParameter(i++, GlobalConstant.RECORD_STATUS_ACTIVE);
    subQuery.setParameter(i++,GlobalConstant.RECORD_STATUS_ACTIVE);
    subQuery.setParameter(i++,GlobalConstant.FALSE);
    subQuery.setParameter(i++,WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
    subQuery.setParameter(i++,MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN);
    subQuery.setParameter(i++,WorkflowStep.END_STEP_SEQ_NO);
    subQuery.pack();
    return subQuery;
  }

  /**
   * Gets a list of progress that the current user record specified in the AbstractSearchForm have permission to monitor to. <br>
   * Basic search can be achieved by,
   *
   * <pre>
   * searchForm.setBasicSearchField(&quot;TRACK_ID&quot;);
   * searchForm.setBasicSearchType(&quot;=&quot;);
   * searchForm.setBasicSearchKeyword(&quot;1&quot;);
   * </pre>
   *
   * Supported searching properties in the (ListWorkflowMonitoringForm)searchForm includes, <table border=1 cellspacing=1 cellpadding=1>
   * <tr>
   * <th>Property</th>
   * <th>Description</th>
   * <th>Possible values</th>
   * </tr>
   * <tr>
   * <td>workflowGroupID</td>
   * <td>the workflow group </td>
   * <td>{@link com.dcivision.workflow.bean.WorkflowRecord#getWorkflowGroupID()}</td>
   * </tr>
   * <tr>
   * <td>submitter</td>
   * <td>workflow submitter</td>
   * <td>{@link com.dcivision.user.bean.UserRecord#getID()}</td>
   * </tr>
   * <tr>
   * <td>trackID</td>
   * <td>related document reference number</td>
   * <td>{@link com.dcivision.workflow.bean.WorkflowProgress#getTrackID()}</td>
   * </tr>
   * <tr>
   * <td>workflowCategoryID</td>
   * <td>the workflow category</td>
   * <td>{@link com.dcivision.workflow.bean.WorkflowRecord#getWorkflowCategoryID()}</td>
   * </tr>
   * <tr>
   * <td>priority</td>
   * <td>the task priority</td>
   * <td>{@link com.dcivision.framework.GlobalConstant#PRIORITY_HIGH},{@link com.dcivision.framework.GlobalConstant#PRIORITY_LOW},{@link com.dcivision.framework.GlobalConstant#PRIORITY_MEDIUM}</td>
   * </tr>
   * <tr>
   * <td>status</td>
   * <td>the task status</td>
   * <td>{@link com.dcivision.workflow.bean.WorkflowProgress#STATUS_PENDING}, {@link com.dcivision.workflow.bean.WorkflowProgress#STATUS_SUBMIT}, etc</td>
   * </tr>
   * <tr>
   * <td>taskType</td>
   * <td>delay task/on time task/all</td>
   * <td>{@link com.dcivision.workflow.web.ListWorkflowMonitoringForm#TASK_TYPE_DELAY},{@link com.dcivision.workflow.web.ListWorkflowMonitoringForm#TASK_TYPE_ON_TIME}</td>
   * </tr>
   * <tr>
   * <td>workflowRecordID</td>
   * <td>the task workflow record id</td>
   * <td>{@link com.dcivision.workflow.bean.WorkflowRecord#getID()}</td>
   * </tr>
   * <tr>
   * <td>datePeriodFrom</td>
   * <td>the task update date</td>
   * <td>yyyy-MM-dd hh:mm:ss</td>
   * </tr>
   * <tr>
   * <td>datePeriodTo</td>
   * <td>the task update date</td>
   * <td>yyyy-MM-dd hh:mm:ss</td>
   * </tr>
   * <tr>
   * <td>relatedObject</td>
   * <td>the task related document</td>
   * <td>{@link com.dcivision.dms.bean.DmsDocument#getReferenceNo()}</td>
   * </tr>
   * <tr>
   * <td>actionTaker</td>
   * <td>task action taker</td>
   * <td>{@link com.dcivision.user.bean.UserRecord#getID()}</td>
   * </tr>
   * <tr>
   * <td>stepName</td>
   * <td>the step name</td>
   * <td>free text</td>
   * </tr>
   * <tr>
   * <td>workflowDescription</td>
   * <td>the workflow description</td>
   * <td>free text</td>
   * </tr>
   * <tr>
   * <td>taskComment</td>
   * <td>the workflow task comment</td>
   * <td>free text</td>
   * </tr>
   * <tr>
   * <td>periodType</td>
   * <td>the task update search type</td>
   * <td>choice</td>
   * </tr>
   * <tr>
   * <td>periodTimes</td>
   * <td>a number for last year/month/day</td>
   * <td>free text</td>
   * </tr>
   * <tr>
   * <td>periodTimeType</td>
   * <td>year/month/day</td>
   * <td></td>
   * </tr>
   * <tr>
   * <td>attachmentName</td>
   * <td>the workflow step attachment name</td>
   * <td>free text</td>
   * </tr>
   * </table>
   *
   * @param searchForm ListWorkflowMonitoringForm object
   * @return List of desired progresses
   * @throws ApplicationException
   * @see com.dcivision.workflow.web.ListWorkflowMonitoringForm
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  /*public synchronized List getListMonitoring(AbstractSearchForm searchForm) throws ApplicationException {
    PreparedStatement preStat = null;
    PreparedStatement preStatCnt = null;
    PreparedStatement preStatTrackID = null;
    ResultSet rs = null;
    ResultSet rsCnt = null;
    ResultSet rsTrackID = null;
    StringBuffer sqlStat = new StringBuffer();
    StringBuffer sqlStatCnt = new StringBuffer();
    List result = new ArrayList();
    int totalNumOfRecord = 0;
    int rowLoopCnt = 0;
    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());
    ListWorkflowMonitoringForm listForm = (ListWorkflowMonitoringForm) searchForm;
    String attachmentName = listForm.getAttachmentName();

    synchronized (dbConn) {
      try {
        MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);

        // * get the list, filter with criteria and track id list
        sqlStat.append("SELECT DISTINCT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, C.WORKFLOW_CODE, C.WORKFLOW_VERSION, C.DESCRIPTION AS WORKFLOW_DESCRIPTION, D.WORKFLOW_CATEGORY_NAME, C.WORKFLOW_CATEGORY_ID, C.ID AS WORKFLOW_RECORD_ID, B.STEP_SEQ, B.STEP_NAME, B.ACTION_TYPE, B.DESCRIPTION AS STEP_DESCRIPTION, B.PRIORITY, B.ON_NO_RESPONSE_AFTER, B.ON_NO_RESPONSE_FOR, U.FULL_NAME , WSTAGE.STAGE_NAME ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP B LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON B.ID=SS.WORKFLOW_STEP_ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON  SS.WORKFLOW_STAGE_ID=WSTAGE.ID, WORKFLOW_RECORD C, SETUP_OPTION_WORKFLOW_CATEGORY D, ");
        sqlStat.append(" WORKFLOW_PROGRESS WPX , USER_RECORD U,MTM_WF_PROGRESS_USER_RECORD PUR ");
        sqlStat.append(" LEFT JOIN WORKFLOW_PROGRESS_ATTACHMENT WPA ON PUR.ID = WPA.MTM_WF_PROGRESS_USER_RECORD_ID ");
        sqlStat.append(" WHERE  A.WORKFLOW_STEP_ID = B.ID AND \n");

        sqlStat.append("       B.WORKFLOW_RECORD_ID = C.ID AND \n");
        sqlStat.append("       C.WORKFLOW_CATEGORY_ID = D.ID AND \n");
        sqlStat.append("       A.TRACK_ID = WPX.TRACK_ID AND \n");
        sqlStat.append("       WPX.ID = PUR.WORKFLOW_PROGRESS_ID AND \n");

        sqlStat.append("       A.RECORD_STATUS = B.RECORD_STATUS AND \n");
        sqlStat.append("       A.RECORD_STATUS = C.RECORD_STATUS AND \n");
        sqlStat.append("       A.RECORD_STATUS = D.RECORD_STATUS AND \n");
        sqlStat.append("       A.RECORD_STATUS = WPX.RECORD_STATUS AND \n");
        sqlStat.append("       A.RECORD_STATUS = PUR.RECORD_STATUS AND \n");
        sqlStat.append("       A.RECORD_STATUS = U.RECORD_STATUS AND \n");

        // filter the Administrator start workflow from background
        sqlStat.append("       (( PUR.USER_RECORD_ID = 0 AND A.SEQ_NO = 1) OR (PUR.USER_RECORD_ID <> 0 ) ) AND \n");

        sqlStat.append("       PUR.USER_RECORD_ID = U.ID AND \n");
        sqlStat.append("       WPX.SEQ_NO = '1'  \n");
        sqlStat.append("       AND B.STEP_SEQ <> ? \n");

        if (!Utility.isEmpty(listForm.getWorkflowGroupID())) {
          sqlStat.append("        AND C.WORKFLOW_GROUP_ID = ? \n");
        }

        if (!Utility.isEmpty(listForm.getSubmitter()) && !listForm.getSubmitter().equals("-1")) {
          // sqlStat.append(" AND A.STATUS = ? \n");
          sqlStat.append("        AND PUR.USER_RECORD_ID = ? \n");
        }

        if (!Utility.isEmpty(listForm.getTrackID())) {
          sqlStat.append("        AND A.TRACK_ID = ? \n");
        }

        // search by Task Comment
        if (!Utility.isEmpty(listForm.getTaskComment())) {
          sqlStat.append("      AND ").append(this.getSearchColumn("REASON", "PUR")).append(" LIKE ?  \n");
        }

        if (!Utility.isEmpty(listForm.getWorkflowCategoryID())) {
          sqlStat.append("       AND C.WORKFLOW_CATEGORY_ID=? \n");
        }
        if (!Utility.isEmpty(listForm.getPriority())) {
          sqlStat.append("       AND A.PROGRESS_PRIORITY=? \n");
        }

        if (!Utility.isEmpty(listForm.getStatus())) {
          sqlStat.append("       AND A.STATUS=? \n");
        }
        if (!Utility.isEmpty(listForm.getTaskType())) {
          sqlStat.append("       AND A.DUE_DATE IS NOT NULL ");//simon_add_for_bug[3976]
          if (ListWorkflowMonitoringForm.TASK_TYPE_DELAY.equals(listForm.getTaskType())) {
            //sqlStat.append("       AND A.DUE_DATE IS NOT NULL ");//simon_del_for_bug[3976]
            //sqlStat.append("       AND ((A.STATUS <> ? AND A.UPDATE_DATE > A.DUE_DATE) OR ");//simon_del_for_bug[3976]
            //sqlStat.append("            (A.STATUS = ? AND ? > A.DUE_DATE)) ");//simon_del_for_bug[3976]
            //simon_add_S_for_bug[3976]
            sqlStat.append("       AND ((A.STATUS <> ? AND A.UPDATE_DATE > A.DUE_DATE) OR ");
            if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE)  {
              sqlStat.append("            (A.STATUS = ? AND TO_DATE(?,'YYYY-MM-DD HH24:MI:SS') > A.DUE_DATE)) ");
            }else{
              sqlStat.append("            (A.STATUS = ? AND ? > A.DUE_DATE)) ");
            }
            //simon_add_E_for_bug[3976]
          } else if (ListWorkflowMonitoringForm.TASK_TYPE_ON_TIME.equals(listForm.getTaskType())) {
            //sqlStat.append("       AND A.STATUS <> ? ");//simon_del_for_bug[3976]
            //sqlStat.append("       AND (A.DUE_DATE IS NULL OR ");//simon_del_for_bug[3976]
            //sqlStat.append("            (A.DUE_DATE IS NOT NULL ");//simon_del_for_bug[3976]
            //sqlStat.append("             AND A.UPDATE_DATE <= A.DUE_DATE)) ");//simon_del_for_bug[3976]
            //simon_add_S_for_bug[3976]
            sqlStat.append("       AND ((A.STATUS <> ? AND A.UPDATE_DATE <= A.DUE_DATE) OR ");
            if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE)  {
              sqlStat.append("            (A.STATUS = ? AND TO_DATE(?,'YYYY-MM-DD HH24:MI:SS') <= A.DUE_DATE)) ");
            }else{
              sqlStat.append("            (A.STATUS = ? AND ? <= A.DUE_DATE)) ");
            }
            //simon_add_E_for_bug[3976]
          }
        }

        if (!Utility.isEmpty(listForm.getWorkflowRecordID())) {
          sqlStat.append("       AND C.ID = ? ");
        }
        if (ListWorkflowMonitoringForm.PERIOD_TIME_TYPE_TIME.equals(listForm.getPeriodType())) {
          if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
            if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && Utility.isEmpty(listForm.getDatePeriodTo())) {
              sqlStat.append("       AND A.UPDATE_DATE >= to_date(? , 'YYYY-MM-DD HH24:MI:SS') ");
            } else if (Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
              sqlStat.append("       AND A.UPDATE_DATE <= to_date(? , 'YYYY-MM-DD HH24:MI:SS') ");
            } else if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
              sqlStat.append("       AND A.UPDATE_DATE BETWEEN to_date(? , 'YYYY-MM-DD HH24:MI:SS') AND to_date(? , 'YYYY-MM-DD HH24:MI:SS') ");
            }
          } else {
            if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && Utility.isEmpty(listForm.getDatePeriodTo())) {
              sqlStat.append("       AND A.UPDATE_DATE >= ? ");
            } else if (Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
              sqlStat.append("       AND A.UPDATE_DATE <= ? ");
            } else if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
              sqlStat.append("       AND A.UPDATE_DATE BETWEEN ? AND ? ");
            }
          }
        } else if (ListWorkflowMonitoringForm.PERIOD_TIME_TYPE_DAYS.equals(listForm.getPeriodType())) {
          if (!Utility.isEmpty(listForm.getPeriodTimes()) && !Utility.isEmpty(listForm.getPeriodTimeType())) {
            if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
              sqlStat.append("       AND A.UPDATE_DATE >= to_date(? , 'YYYY-MM-DD HH24:MI:SS') ");
            } else {
              sqlStat.append("       AND A.UPDATE_DATE >= ? ");
            }
          }
        }

        // where the relatedObject is not NULL,
        if (!Utility.isEmpty(listForm.getRelatedObject())) {
          String workflowTrackIDStr = this.getTrackIDsByRelatedObject(listForm.getRelatedObject(),null);
          sqlStat.append("      AND  " + getInSQL("A.ID", workflowTrackIDStr) + " ");
        }
        if (!Utility.isEmpty(listForm.getActionTaker()) && !listForm.getActionTaker().equals("-1")) {
          sqlStat.append("       AND A.STATUS <> ? ");
          sqlStat.append("       AND A.UPDATER_ID = ? ");
        }
        // Form the WHERE clause for filtering.
        if (searchForm.isSearchable()) {
          String searchField = getSearchColumn(searchForm.getBasicSearchField());
          sqlStat.append(" AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? ");
        }
        // Form the where stepName for filtering
        if (!Utility.isEmpty(listForm.getStepName())) {
          sqlStat.append("      AND ").append(this.getSearchColumn("STEP_NAME", "B")).append("  LIKE ? ");
        }
        // From the where stageName for filtering
        if (!Utility.isEmpty(listForm.getStageName())) {
          sqlStat.append("      AND ").append(this.getSearchColumn("STAGE_NAME", "WSTAGE")).append("  LIKE ? ");
        }

        // Form the where workflow description for filtering
        if (!Utility.isEmpty(listForm.getWorkflowDescription())) {
          sqlStat.append("      AND ").append(this.getSearchColumn("DESCRIPTION", "C")).append("  LIKE  ?  ");
        }

        // search by attachment name.
        if (!Utility.isEmpty(attachmentName)) {
          sqlStat.append("      AND ").append(this.getSearchColumn("ATTACHMENT_NAME", "WPA")).append(" LIKE ?  \n");
        }

        // format the sql for any 'LIKE' statement contained
        sqlStat = this.getFormattedSQL(sqlStat.toString());

        // Form the ORDER clause for sorting.
        if (searchForm.isSortable()) {
          String sortAttribute = searchForm.getSortAttribute();
          if (sortAttribute.indexOf(".") < 0) {
            sortAttribute = "A." + sortAttribute;
          }
          sqlStat.append("ORDER BY " + sortAttribute + " " + searchForm.getSortOrder());
        }
        // Get total number of record return.
        sqlStatCnt = this.getSelectCountSQL(sqlStat);
        sqlStatCnt = sqlStatCnt.replace(0, 15, "SELECT COUNT(DISTINCT(A.ID)) ");

        Timestamp currTime = Utility.getCurrentTimestamp();
        int i = 1;
        preStatCnt = dbConn.prepareStatement(sqlStatCnt.toString());
        this.setPrepareStatement(preStatCnt, i++, WorkflowStep.END_STEP_SEQ_NO);

        if (!Utility.isEmpty(listForm.getWorkflowGroupID())) {
          this.setPrepareStatement(preStatCnt, i++, listForm.getWorkflowGroupID());
        }

        if (!Utility.isEmpty(listForm.getSubmitter()) && !listForm.getSubmitter().equals("-1")) {
          // this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_SUBMIT);

          this.setPrepareStatement(preStatCnt, i++, listForm.getSubmitter());
        }

        if (!Utility.isEmpty(listForm.getTrackID())) {
          this.setPrepareStatement(preStatCnt, i++, listForm.getTrackID());
        }

        if (!Utility.isEmpty(listForm.getTaskComment())) {
          this.setPrepareStatement(preStatCnt, i++, this.getFormattedKeyword(listForm.getTaskComment(), "LIKE"));
        }

        if (!Utility.isEmpty(listForm.getWorkflowCategoryID())) {
          this.setPrepareStatement(preStatCnt, i++, listForm.getWorkflowCategoryID());
        }
        if (!Utility.isEmpty(listForm.getPriority())) {
          this.setPrepareStatement(preStatCnt, i++, listForm.getPriority());
        }
        if (!Utility.isEmpty(listForm.getStatus())) {
          this.setPrepareStatement(preStatCnt, i++, listForm.getStatus());
        }
        if (!Utility.isEmpty(listForm.getTaskType())) {
          if (ListWorkflowMonitoringForm.TASK_TYPE_DELAY.equals(listForm.getTaskType())) {
            this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);
            this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);
            this.setPrepareStatement(preStatCnt, i++, currTime);
          } else {
            this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);
            this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);//simon_add_for_bug[3976]
            this.setPrepareStatement(preStatCnt, i++, currTime);//simon_add_for_bug[3976]
          }
        }

        if (!Utility.isEmpty(listForm.getWorkflowRecordID())) {
          this.setPrepareStatement(preStatCnt, i++, listForm.getWorkflowRecordID());
        }

        if (ListWorkflowMonitoringForm.PERIOD_TIME_TYPE_TIME.equals(listForm.getPeriodType())) {
          if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && Utility.isEmpty(listForm.getDatePeriodTo())) {
            this.setPrepareStatement(preStatCnt, i++, listForm.getDatePeriodFrom());
          } else if (Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
            this.setPrepareStatement(preStatCnt, i++, TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
          } else if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
            this.setPrepareStatement(preStatCnt, i++, listForm.getDatePeriodFrom());
            this.setPrepareStatement(preStatCnt, i++, TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
          }
        } else if (ListWorkflowMonitoringForm.PERIOD_TIME_TYPE_DAYS.equals(listForm.getPeriodType())) {
          if (!Utility.isEmpty(listForm.getPeriodTimes()) && !Utility.isEmpty(listForm.getPeriodTimeType())) {
            java.util.Date currentDate = new java.util.Date();
            Calendar cal = new GregorianCalendar();
            cal.setTime(currentDate);
            StringBuffer rtnDateString = new StringBuffer();
            SimpleDateFormat df = new SimpleDateFormat(SystemParameterFactory.getSystemParameter(SystemParameterConstant.DB_DATETIME_FORMAT));
            if (ListWorkflowMonitoringForm.CALENDAR_TIME_TYPE_DAY.equals(listForm.getPeriodTimeType())) {
              cal.add(Calendar.DAY_OF_MONTH, (0 - new Integer(listForm.getPeriodTimes()).intValue()));
            } else if (ListWorkflowMonitoringForm.CALENDAR_TIME_TYPE_MONTH.equals(listForm.getPeriodTimeType())) {
              cal.add(Calendar.MONTH, (0 - new Integer(listForm.getPeriodTimes()).intValue()));
            } else {
              cal.add(Calendar.YEAR, (0 - new Integer(listForm.getPeriodTimes()).intValue()));
            }
            rtnDateString = df.format(cal.getTime(), rtnDateString, new FieldPosition(0));
            this.setPrepareStatement(preStatCnt, i++, rtnDateString.toString());
          }
        }

        if (!Utility.isEmpty(listForm.getActionTaker()) && !listForm.getActionTaker().equals("-1")) {
          this.setPrepareStatement(preStatCnt, i++, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
          this.setPrepareStatement(preStatCnt, i++, listForm.getActionTaker());
        }

        if (searchForm.isSearchable()) {
          String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
          this.setPrepareStatement(preStatCnt, i++, searchKeyword);
        }
        if (!Utility.isEmpty(listForm.getStepName())) {
          String stepName = this.getFormattedKeyword(listForm.getStepName(), "LIKE");
          this.setPrepareStatement(preStatCnt, i++, stepName);
        }

        if (!Utility.isEmpty(listForm.getStageName())) {
          String stageName = this.getFormattedKeyword(listForm.getStageName(), "LIKE");
          this.setPrepareStatement(preStatCnt, i++, stageName);
        }

        if (!Utility.isEmpty(listForm.getWorkflowDescription())) {
          String workflowDescription = this.getFormattedKeyword(listForm.getWorkflowDescription(), "LIKE");
          this.setPrepareStatement(preStatCnt, i++, workflowDescription);
        }

        if (!Utility.isEmpty(attachmentName)) {
          this.setPrepareStatement(preStatCnt, i++, this.getFormattedKeyword(attachmentName, "LIKE"));
        }

        rsCnt = preStatCnt.executeQuery();
        if (rsCnt.next()) {
          totalNumOfRecord = rsCnt.getInt(1);
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }

        // Retrieve the result in row basis.
        sqlStat = this.getSelectListSQL(sqlStat, startOffset, pageSize);
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        i = 1;
        this.setPrepareStatement(preStat, i++, WorkflowStep.END_STEP_SEQ_NO);

        if (!Utility.isEmpty(listForm.getWorkflowGroupID())) {
          this.setPrepareStatement(preStat, i++, listForm.getWorkflowGroupID());
        }

        if (!Utility.isEmpty(listForm.getSubmitter()) && !listForm.getSubmitter().equals("-1")) {
          // this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_SUBMIT);
          this.setPrepareStatement(preStat, i++, listForm.getSubmitter());
        }

        if (!Utility.isEmpty(listForm.getTrackID())) {
          this.setPrepareStatement(preStat, i++, listForm.getTrackID());
        }

        if (!Utility.isEmpty(listForm.getTaskComment())) {
          this.setPrepareStatement(preStat, i++, this.getFormattedKeyword(listForm.getTaskComment(), "LIKE"));
        }

        if (!Utility.isEmpty(listForm.getWorkflowCategoryID())) {
          this.setPrepareStatement(preStat, i++, listForm.getWorkflowCategoryID());
        }
        if (!Utility.isEmpty(listForm.getPriority())) {
          this.setPrepareStatement(preStat, i++, listForm.getPriority());
        }
        if (!Utility.isEmpty(listForm.getStatus())) {
          this.setPrepareStatement(preStat, i++, listForm.getStatus());
        }
        if (!Utility.isEmpty(listForm.getTaskType())) {
          if (ListWorkflowMonitoringForm.TASK_TYPE_DELAY.equals(listForm.getTaskType())) {
            this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);
            this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);
            this.setPrepareStatement(preStat, i++, currTime);
          } else {
            this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);
            this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);//simon_add_for_bug[3976]
            this.setPrepareStatement(preStat, i++, currTime);//simon_add_for_bug[3976]
          }
        }

        if (!Utility.isEmpty(listForm.getWorkflowRecordID())) {
          this.setPrepareStatement(preStat, i++, listForm.getWorkflowRecordID());
        }
        if (ListWorkflowMonitoringForm.PERIOD_TIME_TYPE_TIME.equals(listForm.getPeriodType())) {
          if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && Utility.isEmpty(listForm.getDatePeriodTo())) {
            this.setPrepareStatement(preStat, i++, listForm.getDatePeriodFrom());
          } else if (Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
            this.setPrepareStatement(preStat, i++, TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
          } else if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
            this.setPrepareStatement(preStat, i++, listForm.getDatePeriodFrom());
            this.setPrepareStatement(preStat, i++, TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
          }
        } else if (ListWorkflowMonitoringForm.PERIOD_TIME_TYPE_DAYS.equals(listForm.getPeriodType())) {
          if (!Utility.isEmpty(listForm.getPeriodTimes()) && !Utility.isEmpty(listForm.getPeriodTimeType())) {
            java.util.Date currentDate = new java.util.Date();
            Calendar cal = new GregorianCalendar();
            cal.setTime(currentDate);
            StringBuffer rtnDateString = new StringBuffer();
            SimpleDateFormat df = new SimpleDateFormat(SystemParameterFactory.getSystemParameter(SystemParameterConstant.DB_DATETIME_FORMAT));
            if (ListWorkflowMonitoringForm.CALENDAR_TIME_TYPE_DAY.equals(listForm.getPeriodTimeType())) {
              cal.add(Calendar.DAY_OF_MONTH, (0 - new Integer(listForm.getPeriodTimes()).intValue()));
            } else if (ListWorkflowMonitoringForm.CALENDAR_TIME_TYPE_MONTH.equals(listForm.getPeriodTimeType())) {
              cal.add(Calendar.MONTH, (0 - new Integer(listForm.getPeriodTimes()).intValue()));
            } else {
              cal.add(Calendar.YEAR, (0 - new Integer(listForm.getPeriodTimes()).intValue()));
            }
            rtnDateString = df.format(cal.getTime(), rtnDateString, new FieldPosition(0));
            this.setPrepareStatement(preStat, i++, rtnDateString.toString());
          }

        }

        if (!Utility.isEmpty(listForm.getActionTaker()) && !listForm.getActionTaker().equals("-1")) {
          this.setPrepareStatement(preStat, i++, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
          this.setPrepareStatement(preStat, i++, listForm.getActionTaker());
        }

        if (searchForm.isSearchable()) {
          String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
          this.setPrepareStatement(preStat, i++, searchKeyword);
        }

        if (!Utility.isEmpty(listForm.getStepName())) {
          String stepName = this.getFormattedKeyword(listForm.getStepName(), "LIKE");
          this.setPrepareStatement(preStat, i++, stepName);
        }

        if (!Utility.isEmpty(listForm.getStageName())) {
          String stageName = this.getFormattedKeyword(listForm.getStageName(), "LIKE");
          this.setPrepareStatement(preStat, i++, stageName);
        }

        if (!Utility.isEmpty(listForm.getWorkflowDescription())) {
          String workflowDescription = this.getFormattedKeyword(listForm.getWorkflowDescription(), "LIKE");
          this.setPrepareStatement(preStat, i++, workflowDescription);
        }

        if (!Utility.isEmpty(attachmentName)) {
          this.setPrepareStatement(preStat, i++, this.getFormattedKeyword(attachmentName, "LIKE"));
        }
        log.debug(preStat.toString());
        rs = preStat.executeQuery();

        this.positionCursor(rs, startOffset, pageSize);

        while (rs.next() && rowLoopCnt < pageSize) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setStageName(getResultSetString(rs, "STAGE_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setSubmitter(getResultSetString(rs, "FULL_NAME"));
          tmpWorkflowProgress.setRecordCount(totalNumOfRecord);
          tmpWorkflowProgress.setRowNum(startOffset++);

          ++rowLoopCnt;
          result.add(tmpWorkflowProgress);
        }
        log.debug("result.size()=" + result.size());
        for (i = 0; i < result.size(); i++) {
          WorkflowProgress tmpWorkflowProgress = (WorkflowProgress) result.get(i);
          List userActorList = stepActorDAO.getListByWorkflowStepID(tmpWorkflowProgress.getWorkflowStepID());
          tmpWorkflowProgress.setUserActorList(userActorList);
          result.set(i, tmpWorkflowProgress);
        }
        log.debug("getListMonitoring about to return");
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }
        try {
          rsTrackID.close();
        } catch (Exception ignore) {
        } finally {
          rsTrackID = null;
        }
        try {
          preStatTrackID.close();
        } catch (Exception ignore) {
        } finally {
          preStatTrackID = null;
        }
      }
    }
  }*/

  //Add BY TC FOR TEST
  public synchronized List getListMonitoring(AbstractSearchForm searchForm) throws ApplicationException {
    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    AbstractQuery query = QueryUtil.createQuery();

    PreparedStatement preStat = null;
    PreparedStatement preStatCnt = null;
    ResultSet rs = null;
    ResultSet rsCnt = null;
    StringBuffer sqlStat = new StringBuffer();
    StringBuffer sqlStatCnt = new StringBuffer();
    List result = new ArrayList();
    int totalNumOfRecord = 0;
    int rowLoopCnt = 0;
    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());
    ListWorkflowMonitoringForm listForm = (ListWorkflowMonitoringForm) searchForm;
    String attachmentName = listForm.getAttachmentName();

    Timestamp currTime = Utility.getCurrentTimestamp();

    synchronized (dbConn) {
      try {
        MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);

        // * get the list, filter with criteria and track id list
        query.append("SELECT DISTINCT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, C.WORKFLOW_CODE, C.WORKFLOW_VERSION, C.DESCRIPTION AS WORKFLOW_DESCRIPTION, D.WORKFLOW_CATEGORY_NAME, C.WORKFLOW_CATEGORY_ID, C.ID AS WORKFLOW_RECORD_ID, B.STEP_SEQ, B.STEP_NAME, B.ACTION_TYPE, B.DESCRIPTION AS STEP_DESCRIPTION, B.PRIORITY, B.ON_NO_RESPONSE_AFTER, B.ON_NO_RESPONSE_FOR, U.FULL_NAME , WSTAGE.STAGE_NAME ");
        query.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP B LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON B.ID=SS.WORKFLOW_STEP_ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON  SS.WORKFLOW_STAGE_ID=WSTAGE.ID, WORKFLOW_RECORD C, SETUP_OPTION_WORKFLOW_CATEGORY D, ");
        query.append(" WORKFLOW_PROGRESS WPX , USER_RECORD U,MTM_WF_PROGRESS_USER_RECORD PUR ");
        query.append(" LEFT JOIN WORKFLOW_PROGRESS_ATTACHMENT WPA ON PUR.ID = WPA.MTM_WF_PROGRESS_USER_RECORD_ID ");
        query.append(" WHERE  A.WORKFLOW_STEP_ID = B.ID AND \n");

        query.append("       B.WORKFLOW_RECORD_ID = C.ID AND \n");
        query.append("       C.WORKFLOW_CATEGORY_ID = D.ID AND \n");
        query.append("       A.TRACK_ID = WPX.TRACK_ID AND \n");
        query.append("       WPX.ID = PUR.WORKFLOW_PROGRESS_ID AND \n");

        query.append("       A.RECORD_STATUS = B.RECORD_STATUS AND \n");
        query.append("       A.RECORD_STATUS = C.RECORD_STATUS AND \n");
        query.append("       A.RECORD_STATUS = D.RECORD_STATUS AND \n");
        query.append("       A.RECORD_STATUS = WPX.RECORD_STATUS AND \n");
        query.append("       A.RECORD_STATUS = PUR.RECORD_STATUS AND \n");
        query.append("       A.RECORD_STATUS = U.RECORD_STATUS AND \n");

        
        query.append("       PUR.USER_RECORD_ID = U.ID AND \n");
        query.append("       WPX.SEQ_NO = '1'  \n");
        query.append("       AND B.STEP_SEQ <> ? \n");

        int i=1;
        query.setParameter(i++, WorkflowStep.END_STEP_SEQ_NO);

        //get the accessible workflow group id;
        List listID = this.sessionContainer.getPermissionManager().getAccessibleObjectIDList(GlobalConstant.OBJECT_TYPE_WORKFLOW, "M");
        if (Utility.isEmpty(listID)) {
          query.append(" AND C.WORKFLOW_GROUP_ID < 0 \n"); // Hide all Workflow.
        } else {
          if (Utility.isEmpty(listForm.getWorkflowGroupID())) {
            query.append(" AND ( C.WORKFLOW_GROUP_ID = ? \n");
            query.setParameter(i++, ((Integer) listID.get(0)).toString());
            for (int j = 1; j < listID.size(); j++) {
              query.append(" OR C.WORKFLOW_GROUP_ID = ? \n");
              query.setParameter(i++, ((Integer) listID.get(j)).toString());
            }
            query.append(") ");
          } else {
            query.append("        AND C.WORKFLOW_GROUP_ID = ? \n");
            query.setParameter(i++, listForm.getWorkflowGroupID());
          }
        }
        if (!Utility.isEmpty(listForm.getSubmitter()) && !listForm.getSubmitter().equals("-1")) {
          // sqlStat.append(" AND A.STATUS = ? \n");
          query.append("        AND PUR.USER_RECORD_ID = ? \n");
          query.setParameter(i++,listForm.getSubmitter());
          //strAndPara.addParameters(listForm.getSubmitter());
        }

        if (!Utility.isEmpty(listForm.getTrackID())) {
          query.append("        AND A.TRACK_ID = ? \n");
          query.setParameter(i++, listForm.getTrackID());
          //strAndPara.addParameters(listForm.getTrackID());
        }

        // search by Task Comment
        if (!Utility.isEmpty(listForm.getTaskComment())) {
          query.append("      AND ").append(this.getSearchColumn("REASON", "PUR")).append(" LIKE ?  \n");
          query.setParameter(i++, this.getFormattedKeyword(listForm.getTaskComment(), "LIKE"));
          //strAndPara.addParameters(this.getFormattedKeyword(listForm.getTaskComment(), "LIKE"));
        }

        if (!Utility.isEmpty(listForm.getWorkflowCategoryID())) {
          query.append("       AND C.WORKFLOW_CATEGORY_ID=? \n");
          query.setParameter(i++, listForm.getWorkflowCategoryID());
          //strAndPara.addParameters(listForm.getWorkflowCategoryID());
        }
        if (!Utility.isEmpty(listForm.getPriority())) {
          query.append("       AND A.PROGRESS_PRIORITY=? \n");
          query.setParameter(i++, listForm.getPriority());
          //strAndPara.addParameters(listForm.getPriority());
        }

        if (!Utility.isEmpty(listForm.getStatus())) {
          query.append("       AND A.STATUS=? \n");
          query.setParameter(i++, listForm.getStatus());
          //strAndPara.addParameters(listForm.getStatus());
        }
        if (!Utility.isEmpty(listForm.getTaskType())) {
          query.append("       AND A.DUE_DATE IS NOT NULL ");//simon_add_for_bug[3976]
          if (ListWorkflowMonitoringForm.TASK_TYPE_DELAY.equals(listForm.getTaskType())) {
            //sqlStat.append("       AND A.DUE_DATE IS NOT NULL ");//simon_del_for_bug[3976]
            //sqlStat.append("       AND ((A.STATUS <> ? AND A.UPDATE_DATE > A.DUE_DATE) OR ");//simon_del_for_bug[3976]
            //sqlStat.append("            (A.STATUS = ? AND ? > A.DUE_DATE)) ");//simon_del_for_bug[3976]
            //simon_add_S_for_bug[3976]
            query.append("       AND ((A.STATUS <> ? AND A.UPDATE_DATE > A.DUE_DATE) OR ");
            query.setParameter(i++, WorkflowProgress.STATUS_PENDING);
            //strAndPara.addParameters(WorkflowProgress.STATUS_PENDING);
            if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE)  {
              query.append("            (A.STATUS = ? AND TO_DATE(?,'YYYY-MM-DD HH24:MI:SS') > A.DUE_DATE)) ");
            }else{
              query.append("            (A.STATUS = ? AND ? > A.DUE_DATE)) ");
            }
            query.setParameter(i++,WorkflowProgress.STATUS_PENDING);
            query.setParameter(i++,currTime);
            //strAndPara.addParameters(WorkflowProgress.STATUS_PENDING);
            //strAndPara.addParameters(currTime);
            //simon_add_E_for_bug[3976]
          } else if (ListWorkflowMonitoringForm.TASK_TYPE_ON_TIME.equals(listForm.getTaskType())) {
            //sqlStat.append("       AND A.STATUS <> ? ");//simon_del_for_bug[3976]
            //sqlStat.append("       AND (A.DUE_DATE IS NULL OR ");//simon_del_for_bug[3976]
            //sqlStat.append("            (A.DUE_DATE IS NOT NULL ");//simon_del_for_bug[3976]
            //sqlStat.append("             AND A.UPDATE_DATE <= A.DUE_DATE)) ");//simon_del_for_bug[3976]
            //simon_add_S_for_bug[3976]
            query.append("       AND ((A.STATUS <> ? AND A.UPDATE_DATE <= A.DUE_DATE) OR ");
            if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE)  {
              query.append("            (A.STATUS = ? AND TO_DATE(?,'YYYY-MM-DD HH24:MI:SS') <= A.DUE_DATE)) ");
            }else{
              query.append("            (A.STATUS = ? AND ? <= A.DUE_DATE)) ");
            }
            query.setParameter(i++,WorkflowProgress.STATUS_PENDING);
            query.setParameter(i++,WorkflowProgress.STATUS_PENDING);
            query.setParameter(i++,currTime);
            //strAndPara.addParameters(WorkflowProgress.STATUS_PENDING);
            //strAndPara.addParameters(WorkflowProgress.STATUS_PENDING);
            //strAndPara.addParameters(currTime);
            //simon_add_E_for_bug[3976]
          }
        }

        if (!Utility.isEmpty(listForm.getWorkflowRecordID())) {
          query.append("       AND C.ID = ? ");
          query.setParameter(i++,listForm.getWorkflowRecordID());
          //strAndPara.addParameters(listForm.getWorkflowRecordID());
        }

        if (ListWorkflowMonitoringForm.PERIOD_TIME_TYPE_TIME.equals(listForm.getPeriodType())) {
          if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
            if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && Utility.isEmpty(listForm.getDatePeriodTo())) {
              query.append("       AND A.UPDATE_DATE >= to_date(? , 'YYYY-MM-DD HH24:MI:SS') ");
              query.setParameter(i++,listForm.getDatePeriodFrom());
              //strAndPara.addParameters(listForm.getDatePeriodFrom());
            } else if (Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
              query.append("       AND A.UPDATE_DATE <= to_date(? , 'YYYY-MM-DD HH24:MI:SS') ");
              query.setParameter(i++,TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
              //strAndPara.addParameters(TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
            } else if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
              query.append("       AND A.UPDATE_DATE BETWEEN to_date(? , 'YYYY-MM-DD HH24:MI:SS') AND to_date(? , 'YYYY-MM-DD HH24:MI:SS') ");
              query.setParameter(i++,listForm.getDatePeriodFrom());
              query.setParameter(i++,TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
              //strAndPara.addParameters(listForm.getDatePeriodFrom());
              //strAndPara.addParameters(TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
            }
          } else {
            if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && Utility.isEmpty(listForm.getDatePeriodTo())) {
              query.append("       AND A.UPDATE_DATE >= ? ");
              query.setParameter(i++,listForm.getDatePeriodFrom());
              //strAndPara.addParameters(listForm.getDatePeriodFrom());
            } else if (Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
              query.append("       AND A.UPDATE_DATE <= ? ");
              query.setParameter(i++,TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
              //strAndPara.addParameters(TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
            } else if (!Utility.isEmpty(listForm.getDatePeriodFrom()) && !Utility.isEmpty(listForm.getDatePeriodTo())) {
              query.append("       AND A.UPDATE_DATE BETWEEN ? AND ? ");
              query.setParameter(i++,listForm.getDatePeriodFrom());
              query.setParameter(i++,TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
              //strAndPara.addParameters(listForm.getDatePeriodFrom());
              //strAndPara.addParameters(TextUtility.dbDateAdder(listForm.getDatePeriodTo(), 1));
            }
          }
        } else if (ListWorkflowMonitoringForm.PERIOD_TIME_TYPE_DAYS.equals(listForm.getPeriodType())) {
          if (!Utility.isEmpty(listForm.getPeriodTimes()) && !Utility.isEmpty(listForm.getPeriodTimeType())) {
            if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
              query.append("       AND A.UPDATE_DATE >= to_date(? , 'YYYY-MM-DD HH24:MI:SS') ");
            } else {
              query.append("       AND A.UPDATE_DATE >= ? ");
            }

            java.util.Date currentDate = new java.util.Date();
            Calendar cal = new GregorianCalendar();
            cal.setTime(currentDate);
            StringBuffer rtnDateString = new StringBuffer();
            SimpleDateFormat df = new SimpleDateFormat(SystemParameterFactory.getSystemParameter(SystemParameterConstant.DB_DATETIME_FORMAT));

            if (ListWorkflowMonitoringForm.CALENDAR_TIME_TYPE_DAY.equals(listForm.getPeriodTimeType())) {
              cal.add(Calendar.DAY_OF_MONTH, (0 - new Integer(listForm.getPeriodTimes()).intValue()));
            } else if (ListWorkflowMonitoringForm.CALENDAR_TIME_TYPE_MONTH.equals(listForm.getPeriodTimeType())) {
              cal.add(Calendar.MONTH, (0 - new Integer(listForm.getPeriodTimes()).intValue()));
            } else {
              cal.add(Calendar.YEAR, (0 - new Integer(listForm.getPeriodTimes()).intValue()));
            }
            rtnDateString = df.format(cal.getTime(), rtnDateString, new FieldPosition(0));

            query.setParameter(i++, rtnDateString.toString());
            //strAndPara.addParameters(rtnDateString.toString());
          }
        }

        // where the relatedObject is not NULL,
        if (!Utility.isEmpty(listForm.getRelatedObject())) {
          //SqlstrAndParameters strAndParaTrackIDs = this.getTrackIDsSQLByRelatedObject(listForm.getRelatedObject(),null);
          //String workflowTrackIDStr = strAndParaTrackIDs.getSqlStr();
          //sqlStat.append("      AND  " + getInSQLStr("A.ID", workflowTrackIDStr) + " ");
          //strAndPara.addAllParameters(strAndParaTrackIDs.getParameters());
          query.append("     AND A.ID IN (");
          query.subQuery(this.getTrackIDsSQLByRelatedObject(listForm.getRelatedObject(),null));
          query.append(" ) \n");
        }
        if (!Utility.isEmpty(listForm.getActionTaker()) && !listForm.getActionTaker().equals("-1")) {
          query.append("       AND A.STATUS <> ? ");
          query.append("       AND A.UPDATER_ID = ? ");
          query.setParameter(i++, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
          query.setParameter(i++, listForm.getActionTaker());
          //strAndPara.addParameters(WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
          //strAndPara.addParameters(listForm.getActionTaker());
        }
        // Form the WHERE clause for filtering.
        if (searchForm.isSearchable()) {
          String searchField = getSearchColumn(searchForm.getBasicSearchField());
          query.append(" AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? ");
          String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
          query.setParameter(i++, searchKeyword);
          //strAndPara.addParameters(searchKeyword);
        }
        // Form the where stepName for filtering
        if (!Utility.isEmpty(listForm.getStepName())) {
          query.append("      AND ").append(this.getSearchColumn("STEP_NAME", "B")).append("  LIKE ? ");
          String stepName = this.getFormattedKeyword(listForm.getStepName(), "LIKE");
          query.setParameter(i++, stepName);
          //strAndPara.addParameters(stepName);
        }
        // From the where stageName for filtering
        if (!Utility.isEmpty(listForm.getStageName())) {
          query.append("      AND ").append(this.getSearchColumn("STAGE_NAME", "WSTAGE")).append("  LIKE ? ");
          String stageName = this.getFormattedKeyword(listForm.getStageName(), "LIKE");
          query.setParameter(i++, stageName);
          //strAndPara.addParameters(stageName);
        }

        // Form the where workflow description for filtering
        if (!Utility.isEmpty(listForm.getWorkflowDescription())) {
          query.append("      AND ").append(this.getSearchColumn("DESCRIPTION", "C")).append("  LIKE  ?  ");
          String workflowDescription = this.getFormattedKeyword(listForm.getWorkflowDescription(), "LIKE");
          query.setParameter(i++, workflowDescription);
          //strAndPara.addParameters(workflowDescription);
        }

        // search by attachment name.
        if (!Utility.isEmpty(attachmentName)) {
          query.append("      AND ").append(this.getSearchColumn("ATTACHMENT_NAME", "WPA")).append(" LIKE ?  \n");
          query.setParameter(i++, this.getFormattedKeyword(attachmentName, "LIKE"));
          //strAndPara.addParameters(this.getFormattedKeyword(attachmentName, "LIKE"));
        }

        // format the sql for any 'LIKE' statement contained
        sqlStat = this.getFormattedSQL(query.toString());

        // Form the ORDER clause for sorting.
        if (searchForm.isSortable()) {
          String sortAttribute = searchForm.getSortAttribute();
          sortAttribute = WorkflowProgressManager.reCombinateSortAttribute(
                   sortAttribute, searchForm.getSortOrder(), "A.");
          sqlStat.append("ORDER BY " + sortAttribute + " " + searchForm.getSortOrder());
        }
        // Get total number of record return.
        query.pack();
        sqlStatCnt = this.getSelectCountSQL(sqlStat);
        sqlStatCnt = sqlStatCnt.replace(0, 15, "SELECT COUNT(DISTINCT(A.ID)) ");


        int offset = 1;
        preStatCnt = dbConn.prepareStatement(sqlStatCnt.toString());

        this.setPreparedStatement(preStatCnt, offset, query.getAllParameters());

        rsCnt = preStatCnt.executeQuery();
        if (rsCnt.next()) {
          totalNumOfRecord = rsCnt.getInt(1);
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }

        // Retrieve the result in row basis.
        sqlStat = this.getSelectListSQL(sqlStat, startOffset, pageSize);
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        offset = 1;
        this.setPreparedStatement(preStat, offset, query.getAllParameters());

        log.debug(sqlStat.toString());

        rs = preStat.executeQuery();

        this.positionCursor(rs, startOffset, pageSize);
        MtmWorkflowProgressUserRecordDAObject mtmUserRecordDAO = new MtmWorkflowProgressUserRecordDAObject(this.sessionContainer, this.dbConn);

        while (rs.next() && rowLoopCnt < pageSize) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setStageName(getResultSetString(rs, "STAGE_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setSubmitter(getResultSetString(rs, "FULL_NAME"));
          tmpWorkflowProgress.setRecordCount(totalNumOfRecord);
          tmpWorkflowProgress.setRowNum(startOffset++);
          ++rowLoopCnt;

          // get the pick up user name
          if (WorkflowProgress.STATUS_IN_PROGRESS.equals(tmpWorkflowProgress.getStatus())) {
            List userNameList = mtmUserRecordDAO.getInProgressUserNameListByWorkflowProgressID(tmpWorkflowProgress.getID());
            tmpWorkflowProgress.setPickUpUserName(userNameList);
          }
          result.add(tmpWorkflowProgress);
        }
        log.debug("result.size()=" + result.size());
        for (i = 0; i < result.size(); i++) {
          WorkflowProgress tmpWorkflowProgress = (WorkflowProgress) result.get(i);
          List userActorList = stepActorDAO.getListByWorkflowStepID(tmpWorkflowProgress.getWorkflowStepID());
          tmpWorkflowProgress.setUserActorList(userActorList);
          result.set(i, tmpWorkflowProgress);
        }
        log.debug("getListMonitoring about to return");
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }
      }
    }
  }
  /**
   * Completes the workflow by the given progress id (Mark the complete_flag of the progress to GlobalConstant.TRUE)
   *
   * @param progressID The workflow progress id
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized void setCompleteFlag(Integer progressID) throws ApplicationException {
    PreparedStatement preStat = null;
    StringBuffer sqlStat = new StringBuffer();

    synchronized (dbConn) {
      try {
        int updateCnt = 0;
        sqlStat.append("UPDATE WORKFLOW_PROGRESS \n");
        sqlStat.append("SET  COMPLETE_FLAG=?\n");
        sqlStat.append("WHERE ID=?");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        setPrepareStatement(preStat, 1, GlobalConstant.TRUE);
        setPrepareStatement(preStat, 2, progressID);
        updateCnt = preStat.executeUpdate();
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_UPDATE_ERROR, e);
      } finally {
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Stops the workflow track by the given track ID
   *
   * @param trackID The workflow track ID
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized void stopWorkflowTrackByTrackID(Integer trackID) throws ApplicationException {
    PreparedStatement preStat = null;
    StringBuffer sqlStat = new StringBuffer();

    synchronized (dbConn) {
      try {
        int updateCnt = 0;
        Timestamp currTime = Utility.getCurrentTimestamp();
        sqlStat.append("UPDATE WORKFLOW_PROGRESS ");
        sqlStat.append("SET  CANCEL_FLAG=?, STATUS=?, UPDATE_COUNT=UPDATE_COUNT+1, UPDATER_ID=?, UPDATE_DATE=? ");
        sqlStat.append("WHERE TRACK_ID=?");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        setPrepareStatement(preStat, 1, GlobalConstant.TRUE);
        setPrepareStatement(preStat, 2, WorkflowProgress.STATUS_CANCEL);
        setPrepareStatement(preStat, 3, sessionContainer.getUserRecordID());
        setPrepareStatement(preStat, 4, currTime);
        setPrepareStatement(preStat, 5, trackID);
        updateCnt = preStat.executeUpdate();
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_UPDATE_ERROR, e);
      } finally {
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Registers a WorkflowProgressListener object
   *
   * @param actionListener The WorkflowProgressListener object
   */
  public void addActionListener(WorkflowProgressListener actionListener) {
    listenerList.add(actionListener);
  }

  /**
   * Unregisters a WorkflowProgressListener object
   *
   * @param actionListener The WorkflowProgressListener object
   */
  public void removmeActionListener(WorkflowProgressListener actionListener) {
    listenerList.remove(actionListener);
  }

  /**
   * Notifies all the registered listener objects for the command
   *
   * @param command The command
   * @param params The parameters
   */
  public void notifyActionListener(Object command, Object[] params) {
    for (int i = 0; i < listenerList.size(); i++) {
      //((WorkflowProgressListener) listenerList.get(i)).actionPerformed(new ProgressActionEvent(this, command, params));
      ((WorkflowProgressListener) listenerList.get(i)).actionPerformed(new ProgressActionEvent(this, command, params),dbConn);
    }
  }


    public synchronized List getTrackIDListForSubmitter(Integer userRecordID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT WP.TRACK_ID ");
        sqlStat.append("FROM WORKFLOW_PROGRESS WP, MTM_WF_PROGRESS_USER_RECORD MPU ");
        sqlStat.append("WHERE WP.ID = MPU.WORKFLOW_PROGRESS_ID ");
        sqlStat.append("AND WP.SEQ_NO = ? AND MPU.USER_RECORD_ID = ? ");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, new Integer(1));
        setPrepareStatement(preStat, 2, userRecordID);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "TRACK_ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }

/*  public synchronized List getTrackIDListForActionTaker(Integer userRecordID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT WP.TRACK_ID ");
        sqlStat.append("FROM WORKFLOW_PROGRESS WP, MTM_WF_PROGRESS_USER_RECORD MPU,MTM_WF_STEP_USER_ACTOR MUA ");
        sqlStat.append("WHERE WP.ID = MPU.WORKFLOW_PROGRESS_ID ");
        sqlStat.append(" AND WP.WORKFLOW_STEP_ID = MUA.WORKFLOW_STEP_ID");
        sqlStat.append(" AND MPU.USER_RECORD_ID = ? ");
        sqlStat.append(" AND MUA.ACTOR_TYPE = ? ");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, userRecordID);
        setPrepareStatement(preStat, 2, MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "TRACK_ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }
*/
  public synchronized List getTrackIDListForActionTakerReportTo(Integer userRecordID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT WP.TRACK_ID ");
        sqlStat.append("FROM WORKFLOW_PROGRESS WP, MTM_WF_PROGRESS_USER_RECORD MPU,MTM_WF_STEP_USER_ACTOR MUA ");
        sqlStat.append("WHERE WP.ID = MPU.WORKFLOW_PROGRESS_ID ");
        sqlStat.append(" AND WP.WORKFLOW_STEP_ID = MUA.WORKFLOW_STEP_ID");
        sqlStat.append(" AND MPU.USER_RECORD_ID = ? ");
        sqlStat.append(" AND MUA.ACTOR_TYPE = ? ");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, userRecordID);
        setPrepareStatement(preStat, 2, MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "TRACK_ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }


  /**
   * Gets the last progress ID by the given step ID within the given track
   *
   * @param trackID The workflow track ID
   * @param workflowStepID The workflow step ID
   * @return Integer The desired progress ID
   * @throws ApplicationException
   */
  public synchronized Integer getLastProgressIDByTrackIDAndStepID(Integer trackID, Integer workflowStepID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    Integer result = null;

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT MAX(WP.ID) ID ");
        sqlStat.append("FROM WORKFLOW_PROGRESS WP ");
        sqlStat.append("WHERE WP.TRACK_ID = ? AND WP.WORKFLOW_STEP_ID = ? ");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, trackID);
        setPrepareStatement(preStat, 2, workflowStepID);
        rs = preStat.executeQuery();
        if (rs.next()) {
          result = getResultSetInteger(rs, "ID");
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return result;
  }


/*    public synchronized List getTrackIDListForMentor(Integer userLinkID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT TRACK_ID ");
        sqlStat.append("FROM WORKFLOW_PROGRESS WP, MTM_WF_PROGRESS_USER_RECORD MPU,USER_RECORD U, STAFF_RECORD S ");
        sqlStat.append("WHERE WP.ID=MPU.WORKFLOW_PROGRESS_ID and U.ID=MPU.USER_RECORD_ID AND U.USER_LINK_ID=S.ID ");
        sqlStat.append("AND WP.SEQ_NO=? AND S.REPORT_TO_STAFF_RECORD_ID=?");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, new Integer(1));
        setPrepareStatement(preStat, 2, userLinkID);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "TRACK_ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }*/


/*    public synchronized List getTrackIDListForPreviousTaskOwner(Integer userRecordID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        String sGroupIDs = "-1";
        String sRoleIDs = "-1";
        List groupList = new ArrayList();
        List roleList = new ArrayList();
        List roleRecordList = new ArrayList();
        List tmpGroupList = new ArrayList();

        MtmUserRecordUserRoleDAObject mtmUserRecordUserRoleDAObject = new MtmUserRecordUserRoleDAObject(sessionContainer, dbConn);
        MtmUserRecordUserGroupDAObject mtmUserRecordUserGroupDAObject = new MtmUserRecordUserGroupDAObject(sessionContainer, dbConn);
        MtmUserGroupUserRoleDAObject mtmUserGroupUserRoleDAObject = new MtmUserGroupUserRoleDAObject(sessionContainer, dbConn);

        groupList = mtmUserRecordUserGroupDAObject.getUserGroupListByUserRecordID(new Integer(userRecordID.toString()));
        roleList = mtmUserRecordUserRoleDAObject.getUserRoleListByUserRecordID(new Integer(userRecordID.toString()));

        for (int i = 0; i < groupList.size(); i++) {
          UserGroup tmpGroup = (UserGroup) groupList.get(i);
          tmpGroupList.add(tmpGroup.getID());
          sGroupIDs += "," + tmpGroup.getID();
        }

        if (!Utility.isEmpty(tmpGroupList)) {
          roleRecordList = mtmUserGroupUserRoleDAObject.getListByUserGroupAry(tmpGroupList);
          for (int i = 0; i < roleRecordList.size(); i++) {
            MtmUserGroupUserRole tmpGroupUserRole = (MtmUserGroupUserRole) roleRecordList.get(i);
            sRoleIDs += "," + tmpGroupUserRole.getUserRoleID();
          }
        }

        for (int i = 0; i < roleList.size(); i++) {
          UserRole tmpRole = (UserRole) roleList.get(i);
          if (sRoleIDs.indexOf(tmpRole.getID().toString()) < 0) {
            sRoleIDs += "," + tmpRole.getID();
          }
        }

        sqlStat.append("SELECT DISTINCT C.TRACK_ID \n");
        sqlStat.append("FROM WORKFLOW_PROGRESS A, \n");
        sqlStat.append(" WORKFLOW_PROGRESS C, \n");
        sqlStat.append(" MTM_WF_PROGRESS_WF_PROGRESS D, \n");
        sqlStat.append(" MTM_WF_STEP_USER_ACTOR E, \n");
        sqlStat.append(" MTM_WF_STEP_USER_ACTOR F \n");
        sqlStat.append("WHERE A.ID = D.PARENT_PROGRESS_ID AND \n");
        sqlStat.append(" C.ID = D.CHILD_PROGRESS_ID AND \n");
        sqlStat.append(" A.WORKFLOW_STEP_ID =E.WORKFLOW_STEP_ID AND \n");
        sqlStat.append(" C.WORKFLOW_STEP_ID = F.WORKFLOW_STEP_ID AND \n");
        sqlStat.append(" ( \n");
        sqlStat.append(" ( E.ACTOR_TYPE = ?AND E.ACTOR_ID = ? ) OR \n");
        sqlStat.append(" ( E.ACTOR_TYPE = ? AND E.ACTOR_ID IN (" + sGroupIDs + " ) ) OR \n");
        sqlStat.append(" ( E.ACTOR_TYPE = ? AND E.ACTOR_ID IN (" + sRoleIDs + " ) ) \n");
        sqlStat.append(" ) AND \n");
        sqlStat.append(" F.ACTOR_TYPE = ? AND \n");
        sqlStat.append(" (C.STATUS = ? OR C.STATUS = ? OR C.STATUS = ?) ");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, GlobalConstant.SUBJECT_TYPE_USER);
        setPrepareStatement(preStat, 2, userRecordID);
        setPrepareStatement(preStat, 3, GlobalConstant.SUBJECT_TYPE_GROUP);
        setPrepareStatement(preStat, 4, GlobalConstant.SUBJECT_TYPE_ROLE);
        setPrepareStatement(preStat, 5, MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_OWNER);
        setPrepareStatement(preStat, 6, WorkflowProgress.STATUS_PENDING);
        setPrepareStatement(preStat, 7, WorkflowProgress.STATUS_IN_PROGRESS);
        setPrepareStatement(preStat, 8, WorkflowProgress.STATUS_LOCK);

        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "TRACK_ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }

    return resultList;
  }*/



/*    public synchronized List getTrackIDListForReportToOfPreviousTask(Integer userLinkID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT C.TRACK_ID ");
        sqlStat.append("FROM WORKFLOW_PROGRESS A, MTM_WF_PROGRESS_USER_RECORD B,WORKFLOW_PROGRESS C, MTM_WF_PROGRESS_WF_PROGRESS D, USER_RECORD E, STAFF_RECORD F, MTM_WF_STEP_USER_ACTOR G ");
        sqlStat.append("WHERE A.ID =B.WORKFLOW_PROGRESS_ID AND ");
        sqlStat.append(" A.ID = D.PARENT_PROGRESS_ID AND ");
        sqlStat.append(" C.ID = D.CHILD_PROGRESS_ID AND ");
        sqlStat.append("E.ID = B.USER_RECORD_ID AND ");
        sqlStat.append(" F.ID = E.USER_LINK_ID AND ");
        sqlStat.append(" C.WORKFLOW_STEP_ID = G.WORKFLOW_STEP_ID AND ");
        sqlStat.append(" G.ACTOR_TYPE = ? AND ");
        sqlStat.append(" F.REPORT_TO_STAFF_RECORD_ID = ? ");
        sqlStat.append(" AND (C.STATUS = ? OR C.STATUS = ? ORC.STATUS=?) ");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER);
        setPrepareStatement(preStat, 2, userLinkID);
        setPrepareStatement(preStat, 3, WorkflowProgress.STATUS_PENDING);
        setPrepareStatement(preStat, 4, WorkflowProgress.STATUS_IN_PROGRESS);
        setPrepareStatement(preStat, 5, WorkflowProgress.STATUS_LOCK);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "TRACK_ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }*/


  /**
   * Gets the user ID of the submitter of the given track
   *
   * @param trackID The workflow track ID
   * @return Integer The user record id of the submitter
   * @throws ApplicationException
   */
  public synchronized Integer getUserIDForWorkflowTrackSubmitter(Integer trackID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT MPU.USER_RECORD_ID ");
        sqlStat.append("FROM WORKFLOW_PROGRESS WP, MTM_WF_PROGRESS_USER_RECORD MPU ");
        sqlStat.append("WHERE WP.ID=MPU.WORKFLOW_PROGRESS_ID ");
        sqlStat.append("AND WP.SEQ_NO=? AND WP.TRACK_ID=? ");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, new Integer(1));
        setPrepareStatement(preStat, 2, trackID);
        rs = preStat.executeQuery();
        if (rs.next()) {
          return getResultSetInteger(rs, "USER_RECORD_ID");
        } else {
          return null;
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Gets a list of user record id that is related to the given step in the given track
   *
   * @param workflowStepID The workflow step id
   * @param trackID The workflow track id
   * @return List of user record id
   * @throws ApplicationException
   */
  public synchronized List getUserIDListForWorkflowStepIDAndWorkflowTrackID(Integer workflowStepID, Integer trackID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();
    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT MPU.USER_RECORD_ID ");
        sqlStat.append("FROM WORKFLOW_PROGRESS WP, MTM_WF_PROGRESS_USER_RECORD MPU ");
        sqlStat.append("WHERE WP.ID=MPU.WORKFLOW_PROGRESS_ID ");
        sqlStat.append("AND WP.WORKFLOW_STEP_ID=? AND WP.TRACK_ID=? ");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, workflowStepID);
        setPrepareStatement(preStat, 2, trackID);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "USER_RECORD_ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }

  /**
   * Gets the StaffRecord of the submitter of the given track
   *
   * @param trackID The workflow track ID
   * @return The StaffRecord of the submitter
   * @throws ApplicationException
   * @see com.dcivision.staff.bean.StaffRecord
   */
  public synchronized com.dcivision.staff.bean.StaffRecord getStaffRecordForWorkflowTrackSubmitter(Integer trackID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    com.dcivision.staff.bean.StaffRecord tmpStaffRecord = null;

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT SR.ID, SR.STAFF_CODE, SR.ID_NO, SR.PASSPORT_NO, SR.ISSUE_COUNTRY_ID, SR.SALUTATION_ID, SR.FIRST_NAME_ENG, SR.LAST_NAME_ENG, SR.FIRST_NAME, SR.LAST_NAME, SR.FULL_NAME, SR.GENDER, SR.BIRTH_DATE, SR.TITLE, SR.AREA_CODE, SR.PHONE_NO, SR.MOBILE_NO, SR.FAX_NO, SR.PAGER_NO, SR.EXTENSION, SR.EMAIL, SR.RENTAL_ADDRESS, SR.MAIL_ADDRESS, SR.REPORT_TO_STAFF_RECORD_ID, SR.LEVEL_1_ID, SR.LEVEL_2_ID, SR.LEVEL_3_ID, SR.LEVEL_4_ID, SR.LEVEL_5_ID, SR.LEVEL_6_ID, SR.LEVEL_7_ID, SR.LEVEL_8_ID, SR.LEVEL_9_ID, SR.LEVEL_10_ID, SR.STATUS, SR.SPOKEN_LANGUAGE, SR.EXPERTISE, SR.ALT_CONTACT_STAFF_RECORD_ID, SR.REMARKS, SR.RECORD_STATUS, SR.UPDATE_COUNT, SR.CREATOR_ID, SR.CREATE_DATE, SR.UPDATER_ID, SR.UPDATE_DATE ");
        // sqlStat.append(" , WP.ID, MPU.WORKFLOW_PROGRESS_ID,MPU.USER_RECORD_ID, UR.ID ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS WP, MTM_WF_PROGRESS_USER_RECORD MPU, USER_RECORD UR, STAFF_RECORD SR ");
        sqlStat.append("WHERE  WP.ID=MPU.WORKFLOW_PROGRESS_ID AND MPU.USER_RECORD_ID=UR.ID AND UR.USER_TYPE='" + UserRecord.USER_TYPE_STAFF + "' AND UR.USER_LINK_ID=SR.ID ");
        sqlStat.append("       AND WP.SEQ_NO=? AND WP.TRACK_ID=? ");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, new Integer(1));
        setPrepareStatement(preStat, 2, trackID);
        rs = preStat.executeQuery();
        if (rs.next()) {
          tmpStaffRecord = new com.dcivision.staff.bean.StaffRecord();
          tmpStaffRecord.setID(getResultSetInteger(rs, "ID"));
          tmpStaffRecord.setStaffCode(getResultSetString(rs, "STAFF_CODE"));
          tmpStaffRecord.setIDNo(getResultSetString(rs, "ID_NO"));
          tmpStaffRecord.setPassportNo(getResultSetString(rs, "PASSPORT_NO"));
          tmpStaffRecord.setIssueCountryID(getResultSetInteger(rs, "ISSUE_COUNTRY_ID"));
          tmpStaffRecord.setSalutationID(getResultSetInteger(rs, "SALUTATION_ID"));
          tmpStaffRecord.setFirstNameEng(getResultSetString(rs, "FIRST_NAME_ENG"));
          tmpStaffRecord.setLastNameEng(getResultSetString(rs, "LAST_NAME_ENG"));
          tmpStaffRecord.setFirstName(getResultSetString(rs, "FIRST_NAME"));
          tmpStaffRecord.setLastName(getResultSetString(rs, "LAST_NAME"));
          tmpStaffRecord.setFullName(getResultSetString(rs, "FULL_NAME"));
          tmpStaffRecord.setGender(getResultSetString(rs, "GENDER"));
          tmpStaffRecord.setBirthDate(getResultSetTimestamp(rs, "BIRTH_DATE"));
          tmpStaffRecord.setTitle(getResultSetString(rs, "TITLE"));
          tmpStaffRecord.setAreaCode(getResultSetString(rs, "AREA_CODE"));
          tmpStaffRecord.setPhoneNo(getResultSetString(rs, "PHONE_NO"));
          tmpStaffRecord.setMobileNo(getResultSetString(rs, "MOBILE_NO"));
          tmpStaffRecord.setFaxNo(getResultSetString(rs, "FAX_NO"));
          tmpStaffRecord.setPagerNo(getResultSetString(rs, "PAGER_NO"));
          tmpStaffRecord.setExtension(getResultSetString(rs, "EXTENSION"));
          tmpStaffRecord.setEmail(getResultSetString(rs, "EMAIL"));
          tmpStaffRecord.setRentalAddress(getResultSetString(rs, "RENTAL_ADDRESS"));
          tmpStaffRecord.setMailAddress(getResultSetString(rs, "MAIL_ADDRESS"));
          tmpStaffRecord.setReportToStaffRecordID(getResultSetInteger(rs, "REPORT_TO_STAFF_RECORD_ID"));
          tmpStaffRecord.setLevel1ID(getResultSetInteger(rs, "LEVEL_1_ID"));
          tmpStaffRecord.setLevel2ID(getResultSetInteger(rs, "LEVEL_2_ID"));
          tmpStaffRecord.setLevel3ID(getResultSetInteger(rs, "LEVEL_3_ID"));
          tmpStaffRecord.setLevel4ID(getResultSetInteger(rs, "LEVEL_4_ID"));
          tmpStaffRecord.setLevel5ID(getResultSetInteger(rs, "LEVEL_5_ID"));
          tmpStaffRecord.setLevel6ID(getResultSetInteger(rs, "LEVEL_6_ID"));
          tmpStaffRecord.setLevel7ID(getResultSetInteger(rs, "LEVEL_7_ID"));
          tmpStaffRecord.setLevel8ID(getResultSetInteger(rs, "LEVEL_8_ID"));
          tmpStaffRecord.setLevel9ID(getResultSetInteger(rs, "LEVEL_9_ID"));
          tmpStaffRecord.setLevel10ID(getResultSetInteger(rs, "LEVEL_10_ID"));
          tmpStaffRecord.setStatus(getResultSetString(rs, "STATUS"));
          tmpStaffRecord.setSpokenLanguage(getResultSetString(rs, "SPOKEN_LANGUAGE"));
          tmpStaffRecord.setExpertise(getResultSetString(rs, "EXPERTISE"));
          tmpStaffRecord.setAlternativeContactStaffRecordID(getResultSetInteger(rs, "ALT_CONTACT_STAFF_RECORD_ID"));
          tmpStaffRecord.setRemarks(getResultSetString(rs, "REMARKS"));
          tmpStaffRecord.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpStaffRecord.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpStaffRecord.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpStaffRecord.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpStaffRecord.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpStaffRecord.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpStaffRecord.setCreatorName(UserInfoFactory.getUserFullName(tmpStaffRecord.getCreatorID()));
          tmpStaffRecord.setUpdaterName(UserInfoFactory.getUserFullName(tmpStaffRecord.getUpdaterID()));
        }
        return (tmpStaffRecord);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Gets a step name of the given task
   *
   * @param wkFlowProgressID The workflow progress id
   * @return The step name
   * @throws ApplicationException
   */
  public synchronized String getStepNameByWkFlowProgressID(Integer wkFlowProgressID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT STEP_NAME ");
        sqlStat.append("FROM WORKFLOW_PROGRESS WP, WORKFLOW_STEP WS ");
        sqlStat.append("WHERE WP.WORKFLOW_STEP_ID=WS.ID ");
        sqlStat.append("AND WP.ID = " + wkFlowProgressID);
        preStat = dbConn.prepareStatement(sqlStat.toString());

        rs = preStat.executeQuery();
        if (rs.next()) {

          return getResultSetString(rs, "STEP_NAME");
        } else {
          return null;
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  private String formatListToSQLString(List listItem) {
    StringBuffer sSQLString = new StringBuffer();
    for (int i = 0; i < listItem.size(); i++) {
      sSQLString.append(((sSQLString.length() > 0) ? "," : "")).append(listItem.get(i));
    }
    return sSQLString.toString();
  }

  private String formatListToSQLString(String className,List listItem){
    StringBuffer sSQLString = new StringBuffer();

    for (int i = 0; listItem!=null&&i < listItem.size(); i++) {
      if (i != 0) {
        sSQLString.append(", ");
      }
      if(UserGroup.class.getName().equals(className))
       {
         UserGroup group = (UserGroup) listItem.get(i);
         sSQLString.append(group.getID());
       }else if(UserRole.class.getName().equals(className)){
         UserRole role = (UserRole) listItem.get(i);
         sSQLString.append(role.getID());
       }
    }
    return sSQLString.toString();
  }
  /**
   * Gets a list of processed task for the current user (or delegated user if delegateUserRecordID is specified in the searchForm)
   *
   * @param searchForm The ListWorkflowProgressForm object
   * @return List of desired progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.web.ListWorkflowProgressForm
   */
 /* public synchronized List getListProcessedForUser(AbstractSearchForm searchForm) throws ApplicationException {
    MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);
    PreparedStatement preStat = null, preStat2 = null, preStatCnt = null;
    ResultSet rs = null, rs2 = null, rsCnt = null;
    StringBuffer sqlStat = new StringBuffer(), sqlStat2 = new StringBuffer();
    StringBuffer sqlStatCnt = new StringBuffer();
    List result = new ArrayList();
    int totalNumOfRecord = 0;
    int rowLoopCnt = 0;
    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());
    String docReferenceNumber = "";
    String trackIDs = "-1";
    String attachmentName = "";
    String progressIDsByAttachmentName = "-1";
    PermissionManager pm = sessionContainer.getPermissionManager();
    Integer userRecordID = pm.getUserRecordID();
    ListWorkflowProgressForm listForm = (ListWorkflowProgressForm) searchForm;
    if (!Utility.isEmpty(listForm.getDelegateUserRecordID())) {
      userRecordID = TextUtility.parseIntegerObj(listForm.getDelegateUserRecordID());
    }
    // get the track ID list by document reference number
    docReferenceNumber = listForm.getDocReferenceNumber();
    if (!Utility.isEmpty(docReferenceNumber)) {

      trackIDs = this.getTrackIDsByRelatedObject(listForm.getDocReferenceNumber(),GlobalConstant.RECORD_STATUS_ACTIVE);
    }
    // get the progress ID list by attachment name
    attachmentName = listForm.getAttachmentName();
    if (!Utility.isEmpty(attachmentName)) {
      List tmpWfProgressIDList = this.getProgressIDListByAttachmentName(attachmentName);
      for (int k = 0; k < tmpWfProgressIDList.size(); k++) {
        progressIDsByAttachmentName += "," + (tmpWfProgressIDList.get(k).toString());
      }
    }
    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT  DISTINCT WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.SEQ_NO, WP.STATUS, WP.POST_PROGRESS, WP.DUE_DATE, WP.NEXT_STEP_DUE_DATES, WP.PROGRESS_PRIORITY, WP.USER_DEF_1, WP.USER_DEF_2, WP.USER_DEF_3, WP.USER_DEF_4, WP.USER_DEF_5, WP.RECORD_STATUS, WP.UPDATE_COUNT, WP.CREATOR_ID, WP.CREATE_DATE, WP.UPDATER_ID, WP.UPDATE_DATE AS UPDATE_DATE, WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR , WSTAGE.STAGE_NAME \n");
        sqlStat.append("FROM    WORKFLOW_STEP WS LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON WS.ID=SS.WORKFLOW_STEP_ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON  SS.WORKFLOW_STAGE_ID=WSTAGE.ID, WORKFLOW_PROGRESS WP, MTM_WF_PROGRESS_USER_RECORD MWPUR, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC \n");
        sqlStat.append("WHERE   WR.ID = WS.WORKFLOW_RECORD_ID AND \n");
        sqlStat.append("        WR.WORKFLOW_CATEGORY_ID = SOWC.ID AND \n");
        sqlStat.append("        WS.ID = WP.WORKFLOW_STEP_ID AND \n");
        sqlStat.append("        WP.ID = MWPUR.WORKFLOW_PROGRESS_ID AND \n");
        sqlStat.append("        WR.RECORD_STATUS = ? AND \n");
        sqlStat.append("        WP.CANCEL_FLAG = ? AND \n");
        sqlStat.append("        WS.ACTION_TYPE <> ? AND \n");
        if (searchForm instanceof ListWorkflowProgressForm && !Utility.isEmpty(((ListWorkflowProgressForm) searchForm).getWorkflowTrackID())) {
          sqlStat.append("      ((  MWPUR.WORKFLOW_ACTION <> ? AND \n");
          sqlStat.append("        MWPUR.WORKFLOW_ACTION <> ? ) OR \n");
          sqlStat.append("        WP.STATUS =? ) AND \n");
          // search by the workflow track id ;
          sqlStat.append("        WP.TRACK_ID=?  AND \n");
        } else {
          sqlStat.append("        MWPUR.WORKFLOW_ACTION <> ? AND \n");
          sqlStat.append("        MWPUR.WORKFLOW_ACTION <> ? AND \n");
        }
        sqlStat.append("        MWPUR.USER_RECORD_ID = ?  \n");
        sqlStat.append("        AND (SS.RECORD_STATUS = ?  OR SS.RECORD_STATUS IS NULL) \n ");// simon

        // Form the WHERE clause for filtering.
        String searchDateFrom = null;
        String searchDateTo = null;

        if (searchForm.isSearchable()) {
          String searchField = getSearchColumn(searchForm.getBasicSearchField(), "WP");
          sqlStat.append("AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? ");
        }
        if (searchForm instanceof ListWorkflowProgressForm) {
          ListWorkflowProgressForm wkprogressForm = (ListWorkflowProgressForm) searchForm;
          // search by the arrival or due date
          if ((!Utility.isEmpty(wkprogressForm.getDateFrom())) || (!Utility.isEmpty(wkprogressForm.getDateTo()))) {
            String searchField = "";
            if (WorkflowProgress.SEARCH_ARRIVAL_DATE.equals(wkprogressForm.getDateSearchField())) {
              searchField = "WP.CREATE_DATE";
              searchDateFrom = wkprogressForm.getDateFrom();
              searchDateTo = wkprogressForm.getDateTo();

              sqlStat.append(" AND ");

              if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
                if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
                    + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
              } else {
                if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
                else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
                else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
              }
            } else if (WorkflowProgress.SEARCH_DUE_DATE.equals(wkprogressForm.getDateSearchField())) {
              //sqlStat.append(" AND  (");//simon_del
              sqlStat.append(" AND ");//simon_add
              //searchField = "WS.ON_NO_RESPONSE_AFTER";//simon_del
              searchField = "WP.DUE_DATE";//simon_add
              searchDateFrom = wkprogressForm.getDateFrom();
              searchDateTo = wkprogressForm.getDateTo();
              //simon_add_S
              if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
                  if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                    sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
                      + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                  else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo)))
                    sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                  else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                    sqlStat.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                } else {
                  if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                    sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
                  else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo)))
                    sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
                  else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                    sqlStat.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
                }
              //simon_add_E
              /*simon_del_S
              if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
                if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
                    + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
              } else {
                if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
                else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
                else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
              }
              sqlStat.append(" OR ");
              // searchField ="DATE_ADD(WP.CREATE_DATE, WS.ON_NO_RESPONSE_FOR)";
              switch (DataSourceFactory.getDatabaseType()) {
              case DataSourceFactory.DB_MYSQL:
                searchField = "DATE_ADD(WP.CREATE_DATE, INTERVAL WS.ON_NO_RESPONSE_FOR DAY)";
                break;

              case DataSourceFactory.DB_ORACLE:
                searchField = "(WP.CREATE_DATE +  WS.ON_NO_RESPONSE_FOR)";
                break;

              case DataSourceFactory.DB_MSSQL:
                searchField = "DATEADD('d',WS.ON_NO_RESPONSE,WP.CREATE_DATE)";
                break;
              }
              if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
                if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
                    + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
              } else {
                if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
                else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
                else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo)))
                  sqlStat.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
              }
              sqlStat.append(" ) ");
              ////////simon_del_E
            }

          }
          // search by who send the workflow
          if (!Utility.isEmpty(wkprogressForm.getFromWhom()) && !wkprogressForm.getFromWhom().equals("-1")) {
            sqlStat.append(" AND ");
            sqlStat.append("WP.CREATOR_ID = " + wkprogressForm.getFromWhom());
          }

          // search by the priority of the workflow
          if (!Utility.isEmpty(wkprogressForm.getPriority())) {
            sqlStat.append(" AND ");
            sqlStat.append("WP.PROGRESS_PRIORITY = '" + wkprogressForm.getPriority() + "'");
          }

          // search by the document reference number
          if (!Utility.isEmpty(docReferenceNumber)) {
            sqlStat.append("        AND " + getInSQL("WP.ID", trackIDs) + " \n");
          }

          // search by the attachment Name
          if (!Utility.isEmpty(attachmentName)) {
            sqlStat.append("        AND " + getInSQL("WP.ID", progressIDsByAttachmentName) + " \n");
          }

          // search by the task comment
          if (!Utility.isEmpty(listForm.getTaskComment())) {
            sqlStat.append("        AND ").append(this.getSearchColumn("REASON", "MWPUR")).append(" LIKE  ?  \n");
          }
          if (Utility.isEmpty(((ListWorkflowProgressForm) searchForm).getWorkflowTrackID()) && !Utility.isEmpty(((ListWorkflowProgressForm) searchForm).getDelegateUserRecordID())) {
            sqlStat2.append("SELECT WORKFLOW_PROGRESS_ID ");
            sqlStat2.append("FROM MTM_WF_PROGRESS_USER_RECORD ");
            sqlStat2.append("WHERE USER_RECORD_ID = " + userRecordID.toString());
            sqlStat2.append(" AND DELEGATE_USER_RECORD_ID = " + sessionContainer.getUserRecordID().toString());
            sqlStat2.append(" AND WORKFLOW_ACTION <> '" + WorkflowProgress.STATUS_IN_PROGRESS + "' ");
            sqlStat2.append(" AND WORKFLOW_ACTION <> '" + WorkflowProgress.STATUS_PENDING + "' ");
            preStat2 = dbConn.prepareStatement(sqlStat2.toString());
            rs2 = preStat2.executeQuery();
            String progressID = "";
            while (rs2.next()) {
              progressID += ((progressID.length() > 0) ? "," : "") + getResultSetInteger(rs2, "WORKFLOW_PROGRESS_ID");
            }
            if (Utility.isEmpty(progressID)) {
              progressID += -1;
            }
            sqlStat.append("           AND " + getInSQL("WP.ID", progressID) + " ");

            try {
              rs2.close();
            } catch (Exception ignore) {
            } finally {
              rs2 = null;
            }
            try {
              preStat2.close();
            } catch (Exception ignore) {
            } finally {
              preStat2 = null;
            }

          }

        }
        // Get total number of record return.
        sqlStatCnt = this.getSelectCountSQL(sqlStat);

        // change the "SELECT COUNT(*)" to "SELECT COUNT(DISTINCT WP.ID)"
        StringBuffer sbTmp = sqlStatCnt;
        sqlStatCnt = new StringBuffer("SELECT COUNT(DISTINCT WP.ID) FROM ");

        int idx = sbTmp.indexOf("FROM ");
        sqlStatCnt.append(sbTmp.substring(idx + 5));
        if (sqlStatCnt.indexOf("ORDER BY") >= 0) {
          sqlStatCnt = new StringBuffer(sqlStatCnt.substring(0, sqlStatCnt.indexOf("ORDER BY") - 1));
        }
        preStatCnt = dbConn.prepareStatement(sqlStatCnt.toString());

        int i = 1;
        this.setPrepareStatement(preStatCnt, i++, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStatCnt, i++, GlobalConstant.FALSE);
        this.setPrepareStatement(preStatCnt, i++, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
        if (searchForm instanceof ListWorkflowProgressForm && !Utility.isEmpty(((ListWorkflowProgressForm) searchForm).getWorkflowTrackID())) {
          this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);
          this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_IN_PROGRESS);
          this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);
          this.setPrepareStatement(preStatCnt, i++, new Integer(((ListWorkflowProgressForm) searchForm).getWorkflowTrackID()));
        } else {
          this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);
          this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_IN_PROGRESS);
        }
        this.setPrepareStatement(preStatCnt, i++, userRecordID.toString());
        this.setPrepareStatement(preStatCnt, i++, GlobalConstant.RECORD_STATUS_ACTIVE);// simon
        if (searchForm.isSearchable()) {
          String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
          this.setPrepareStatement(preStatCnt, i++, searchKeyword);
        }

        // search by the task comment
        if (!Utility.isEmpty(listForm.getTaskComment())) {
          this.setPrepareStatement(preStatCnt, i++, this.getFormattedKeyword(listForm.getTaskComment(), "LIKE"));
        }

        rsCnt = preStatCnt.executeQuery();
        while (rsCnt.next()) {
          totalNumOfRecord += rsCnt.getInt(1);
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }

        // Form the ORDER clause for sorting.
        if (searchForm.isSortable()) {
          String sortAttribute = searchForm.getSortAttribute();
          if (sortAttribute.indexOf(".") < 0) {
            // sortAttribute = "WP." + sortAttribute;
          }
          sqlStat=this.getUnionOrderSQL(sqlStat, sortAttribute, searchForm.getSortOrder());
          //sqlStat.append(" ORDER BY " + sortAttribute + " " + searchForm.getSortOrder());
        }
        log.debug("sqlStat: \n" + sqlStat.toString());
        // Retrieve the result in row basis.
        sqlStat = this.getSelectListSQL(sqlStat, startOffset, pageSize);
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        i = 1;
        this.setPrepareStatement(preStat, i++, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, i++, GlobalConstant.FALSE);
        this.setPrepareStatement(preStat, i++, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
        if (searchForm instanceof ListWorkflowProgressForm && !Utility.isEmpty(((ListWorkflowProgressForm) searchForm).getWorkflowTrackID())) {
          this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);
          this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_IN_PROGRESS);
          this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);
          this.setPrepareStatement(preStat, i++, new Integer(((ListWorkflowProgressForm) searchForm).getWorkflowTrackID()));
        } else {
          this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);
          this.setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_IN_PROGRESS);
        }
        this.setPrepareStatement(preStat, i++, userRecordID);
        this.setPrepareStatement(preStat, i++, GlobalConstant.RECORD_STATUS_ACTIVE);// simon
        if (searchForm.isSearchable()) {
          String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
          this.setPrepareStatement(preStat, i++, searchKeyword);
        }
        // search by the task comment
        if (!Utility.isEmpty(listForm.getTaskComment())) {
          this.setPrepareStatement(preStat, i++, this.getFormattedKeyword(listForm.getTaskComment(), "LIKE"));
        }
        rs = preStat.executeQuery();
        this.positionCursor(rs, startOffset, pageSize);
        while (rs.next() && rowLoopCnt < pageSize) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setStageName(getResultSetString(rs, "STAGE_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));
          tmpWorkflowProgress.setRecordCount(totalNumOfRecord);
          tmpWorkflowProgress.setRowNum(startOffset++);
          ++rowLoopCnt;
          result.add(tmpWorkflowProgress);
        }
        for (i = 0; i < result.size(); i++) {
          WorkflowProgress tmpWorkflowProgress = (WorkflowProgress) result.get(i);
          List userActorList = stepActorDAO.getListByWorkflowStepID(tmpWorkflowProgress.getWorkflowStepID());
          tmpWorkflowProgress.setUserActorList(userActorList);
          result.set(i, tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }*/

//ADD BY TC FOR SUBQUERY
  public synchronized List getListProcessedForUser(AbstractSearchForm searchForm) throws ApplicationException {
    MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);
    PreparedStatement preStat = null,  preStatCnt = null;
    ResultSet rs = null,  rsCnt = null;
    StringBuffer sqlStat1 = new StringBuffer();
    AbstractQuery sqlStat = new SubQuery();
    StringBuffer sqlStat2 = new StringBuffer();
    StringBuffer sqlStatCnt = new StringBuffer();
    List result = new ArrayList();
    int totalNumOfRecord = 0;

    int startOffset = TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = TextUtility.parseInteger(searchForm.getPageOffset());
    String docReferenceNumber = "";
    String relatedObject ="";
    //String trackIDs = "-1";
    AbstractQuery trackIDs = null;
    String attachmentName = "";
    //String progressIDsByAttachmentName = "-1";
    AbstractQuery progressIDsByAttachmentName = null;
    PermissionManager pm = sessionContainer.getPermissionManager();
    Integer userRecordID = pm.getUserRecordID();
    ListWorkflowProgressForm listForm = (ListWorkflowProgressForm) searchForm;

    if (!Utility.isEmpty(listForm.getDelegateUserRecordID())) {
      userRecordID = TextUtility.parseIntegerObj(listForm.getDelegateUserRecordID());
    }
    // get the track ID list by document reference number
    docReferenceNumber = listForm.getDocReferenceNumber();
    if (!Utility.isEmpty(docReferenceNumber)) {
      trackIDs = this.getTrackIDsSQLByRelatedObject(listForm.getDocReferenceNumber(),GlobalConstant.RECORD_STATUS_ACTIVE);
      //trackIDs = this.getTrackIDsByRelatedObject(listForm.getDocReferenceNumber(),GlobalConstant.RECORD_STATUS_ACTIVE);
    }
    
    // get the track ID list by related object
    AbstractQuery trackIDsByRelatedObject = null;
    relatedObject=listForm.getReferenceNumber();
    if (!Utility.isEmpty(relatedObject)) {
      trackIDsByRelatedObject = this.getTrackIDsSQLByRelatedObject(relatedObject,GlobalConstant.RECORD_STATUS_ACTIVE);
    }
    // get the progress ID list by attachment name
    attachmentName = listForm.getAttachmentName();
    if (!Utility.isEmpty(attachmentName)) {
      //List tmpWfProgressIDList = this.getProgressIDListByAttachmentName(attachmentName);
      //for (int k = 0; k < tmpWfProgressIDList.size(); k++) {
       // progressIDsByAttachmentName += "," + (tmpWfProgressIDList.get(k).toString());
     // }
      progressIDsByAttachmentName = this.getProgressIDsSQLByAttachmentName(attachmentName);
    }
    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT  WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.SEQ_NO, WP.STATUS, WP.POST_PROGRESS, WP.DUE_DATE,  WP.UPDATE_DATE AS UPDATE_DATE, WP.NEXT_STEP_DUE_DATES, WP.PROGRESS_PRIORITY,  WP.RECORD_STATUS,  WP.CREATOR_ID, WP.CREATE_DATE, WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE,   WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE,  WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR \n");
        sqlStat.append("FROM    WORKFLOW_STEP WS , WORKFLOW_PROGRESS WP, MTM_WF_PROGRESS_USER_RECORD MWPUR, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC \n");
        sqlStat.append("WHERE   WR.ID = WS.WORKFLOW_RECORD_ID AND \n");
        sqlStat.append("        WR.WORKFLOW_CATEGORY_ID = SOWC.ID AND \n");
        sqlStat.append("        WS.ID = WP.WORKFLOW_STEP_ID AND \n");
        sqlStat.append("        WP.ID = MWPUR.WORKFLOW_PROGRESS_ID AND \n");
        sqlStat.append("        WR.RECORD_STATUS = ? AND \n");
        // Display the cancel progress in processed list page.
        // sqlStat.append("        WP.CANCEL_FLAG = ? AND \n");
        sqlStat.append("        WS.ACTION_TYPE <> ? AND \n");
        if (searchForm instanceof ListWorkflowProgressForm && !Utility.isEmpty(((ListWorkflowProgressForm) searchForm).getWorkflowTrackID())) {
          sqlStat.append("      ((  MWPUR.WORKFLOW_ACTION <> ? AND \n");
          sqlStat.append("        MWPUR.WORKFLOW_ACTION <> ? ) OR \n");
          sqlStat.append("        WP.STATUS =? ) AND \n");
          // search by the workflow track id ;
          sqlStat.append("        WP.TRACK_ID=?  AND \n");
        } else {
          sqlStat.append("        MWPUR.WORKFLOW_ACTION <> ? AND \n");
          sqlStat.append("        MWPUR.WORKFLOW_ACTION <> ? AND \n");
        }
        sqlStat.append("        MWPUR.USER_RECORD_ID = ?  \n");
       // sqlStat.append("        AND (SS.RECORD_STATUS = ?  OR SS.RECORD_STATUS IS NULL) \n ");// simon

        // Form the WHERE clause for filtering.
        String searchDateFrom = null;
        String searchDateTo = null;

        if (searchForm.isSearchable()) {
          String searchField = getSearchColumn(searchForm.getBasicSearchField(), "WP");
          sqlStat.append("AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? ");
        }
        if (searchForm instanceof ListWorkflowProgressForm) {
          ListWorkflowProgressForm wkprogressForm = (ListWorkflowProgressForm) searchForm;
          // search by the arrival or due date
          if ((!Utility.isEmpty(wkprogressForm.getDateFrom())) || (!Utility.isEmpty(wkprogressForm.getDateTo()))) {
            String searchField = "";
            if (WorkflowProgress.SEARCH_ARRIVAL_DATE.equals(wkprogressForm.getDateSearchField())) {
              searchField = "WP.CREATE_DATE";
              searchDateFrom = wkprogressForm.getDateFrom();
              searchDateTo = wkprogressForm.getDateTo();

              sqlStat.append(" AND ");

              if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
                if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
                  sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS')  AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
                    + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
                  sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
                  sqlStat.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                }
              } else {
                if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
                  sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
                } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
                  sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
                } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
                  sqlStat.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
                }
              }
            } else if (WorkflowProgress.SEARCH_DUE_DATE.equals(wkprogressForm.getDateSearchField())) {
              //sqlStat.append(" AND  (");//simon_del
              sqlStat.append(" AND ");//simon_add
              //searchField = "WS.ON_NO_RESPONSE_AFTER";//simon_del
              searchField = "WP.DUE_DATE";//simon_add
              searchDateFrom = wkprogressForm.getDateFrom();
              searchDateTo = wkprogressForm.getDateTo();
              //simon_add_S
              if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE) {
                  if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
                    sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') AND " + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1)
                      + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                  } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
                    sqlStat.append(" (" + searchField + " >= to_date('" + searchDateFrom + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                  } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
                    sqlStat.append(" (" + searchField + " < to_date('" + TextUtility.dbDateAdder(searchDateTo, 1) + "', 'YYYY-MM-DD HH24:MI:SS') ) ");
                  }
                } else {
                  if ((!Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
                    sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "' AND " + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
                  } else if ((!Utility.isEmpty(searchDateFrom)) && (Utility.isEmpty(searchDateTo))) {
                    sqlStat.append(" (" + searchField + " >= '" + searchDateFrom + "') ");
                  } else if ((Utility.isEmpty(searchDateFrom)) && (!Utility.isEmpty(searchDateTo))) {
                    sqlStat.append(" (" + searchField + " < '" + TextUtility.dbDateAdder(searchDateTo, 1) + "') ");
                  }
                }

            }

          }
          // search by who send the workflow
          if (!Utility.isEmpty(wkprogressForm.getFromWhom()) && !wkprogressForm.getFromWhom().equals("-1")) {
            sqlStat.append(" AND ");
            sqlStat.append("WP.CREATOR_ID = " + wkprogressForm.getFromWhom());
          }

          // search by the priority of the workflow
          if (!Utility.isEmpty(wkprogressForm.getPriority())) {
            sqlStat.append(" AND ");
            sqlStat.append("WP.PROGRESS_PRIORITY = '" + wkprogressForm.getPriority() + "'");
          }

          // search by the document reference number
          if (!Utility.isEmpty(docReferenceNumber)) {
            sqlStat.append("        AND WP.ID IN(").subQuery(trackIDs).append(") \n");
          }
          
          // search by the related object.
          if (!Utility.isEmpty(relatedObject)) {
            sqlStat.append("        AND WP.ID IN(").subQuery(trackIDsByRelatedObject).append(") \n");
          }
          
          // search by the attachment Name
          if (!Utility.isEmpty(attachmentName)) {
            sqlStat.append("        AND WP.ID IN(").subQuery(progressIDsByAttachmentName).append(") \n");
          }

          // search by the task comment
          if (!Utility.isEmpty(listForm.getTaskComment())) {
            sqlStat.append("        AND ").append(this.getSearchColumn("REASON", "MWPUR")).append(" LIKE  ?  \n");
          }
          if (Utility.isEmpty(((ListWorkflowProgressForm) searchForm).getWorkflowTrackID()) && !Utility.isEmpty(((ListWorkflowProgressForm) searchForm).getDelegateUserRecordID())) {
            sqlStat2.append("SELECT WORKFLOW_PROGRESS_ID ");
            sqlStat2.append("FROM MTM_WF_PROGRESS_USER_RECORD ");
            sqlStat2.append("WHERE USER_RECORD_ID = " + userRecordID.toString());
            sqlStat2.append(" AND DELEGATE_USER_RECORD_ID = " + sessionContainer.getUserRecordID().toString());
            sqlStat2.append(" AND WORKFLOW_ACTION <> '" + WorkflowProgress.STATUS_IN_PROGRESS + "' ");
            sqlStat2.append(" AND WORKFLOW_ACTION <> '" + WorkflowProgress.STATUS_PENDING + "' ");

            sqlStat.append("           AND WP.ID IN ("+sqlStat2.toString()+")\n ");



          }

        }
        //--set the parameters
        int i = 1;
        sqlStat.setParameter(i++, GlobalConstant.RECORD_STATUS_ACTIVE);
        // sqlStat.setParameter(i++, GlobalConstant.FALSE);
        sqlStat.setParameter(i++, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
        if (searchForm instanceof ListWorkflowProgressForm && !Utility.isEmpty(((ListWorkflowProgressForm) searchForm).getWorkflowTrackID())) {
          sqlStat.setParameter( i++, WorkflowProgress.STATUS_PENDING);
          sqlStat.setParameter( i++, WorkflowProgress.STATUS_IN_PROGRESS);
          sqlStat.setParameter( i++, WorkflowProgress.STATUS_PENDING);
          sqlStat.setParameter(i++, new Integer(((ListWorkflowProgressForm) searchForm).getWorkflowTrackID()));
        } else {
          sqlStat.setParameter( i++, WorkflowProgress.STATUS_PENDING);
          sqlStat.setParameter( i++, WorkflowProgress.STATUS_IN_PROGRESS);
        }
        sqlStat.setParameter( i++, userRecordID.toString());
        //sqlStat.setParameter(i++, GlobalConstant.RECORD_STATUS_ACTIVE);// simon
        if (searchForm.isSearchable()) {
          String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
          sqlStat.setParameter(i++, searchKeyword);
        }

        // search by the task comment
        if (!Utility.isEmpty(listForm.getTaskComment())) {
          sqlStat.setParameter(i++, this.getFormattedKeyword(listForm.getTaskComment(), "LIKE"));
        }

        sqlStat.pack();//---

        // Get total number of record return and format the sql for any 'LIKE' statement contained.
        sqlStatCnt = this.getSelectCountSQL(this.getFormattedSQL(sqlStat.toString()));

        // change the "SELECT COUNT(*)" to "SELECT COUNT(DISTINCT WP.ID)"
        StringBuffer sbTmp = sqlStatCnt;
        sqlStatCnt = new StringBuffer("SELECT COUNT(DISTINCT WP.ID) FROM ");

        int idx = sbTmp.indexOf("FROM ");
        sqlStatCnt.append(sbTmp.substring(idx + 5));
        if (sqlStatCnt.indexOf("ORDER BY") >= 0) {
          sqlStatCnt = new StringBuffer(sqlStatCnt.substring(0, sqlStatCnt.indexOf("ORDER BY") - 1));
        }
        preStatCnt = dbConn.prepareStatement(sqlStatCnt.toString());

        this.setPreparedStatement(preStatCnt, 1, sqlStat.getAllParameters());

        rsCnt = preStatCnt.executeQuery();
        while (rsCnt.next()) {
          totalNumOfRecord += rsCnt.getInt(1);
        }
        try {
          rsCnt.close();
        } catch (Exception ignore) {
        } finally {
          rsCnt = null;
        }
        try {
          preStatCnt.close();
        } catch (Exception ignore) {
        } finally {
          preStatCnt = null;
        }

        // Form the ORDER clause for sorting.
        if (searchForm.isSortable()) {
          String sortAttribute = searchForm.getSortAttribute();
          sortAttribute = WorkflowProgressManager.reCombinateSortAttribute(
              sortAttribute, searchForm.getSortOrder(), "");
          sqlStat1=this.getUnionOrderSQL(new StringBuffer(sqlStat.toString()), sortAttribute, searchForm.getSortOrder());
          //sqlStat.append(" ORDER BY " + sortAttribute + " " + searchForm.getSortOrder());
        }
        log.debug("sqlStat: \n" + sqlStat1.toString());
        // Retrieve the result in row basis.
        sqlStat1 = this.getSelectListSQL(sqlStat1, startOffset, pageSize);
        preStat = dbConn.prepareStatement(sqlStat1.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPreparedStatement(preStat, 1, sqlStat.getAllParameters());
        rs = preStat.executeQuery();
        this.positionCursor(rs, startOffset, pageSize);
        /*while (rs.next() && rowLoopCnt < pageSize) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setStageName(getResultSetString(rs, "STAGE_NAME"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));
          tmpWorkflowProgress.setRecordCount(totalNumOfRecord);
          tmpWorkflowProgress.setRowNum(startOffset++);
          ++rowLoopCnt;
          result.add(tmpWorkflowProgress);
        }*/
        result = this.getResultList(rs, totalNumOfRecord, searchForm);
        for (i = 0; i < result.size(); i++) {
          WorkflowProgress tmpWorkflowProgress = (WorkflowProgress) result.get(i);
          List userActorList = stepActorDAO.getListByWorkflowStepID(tmpWorkflowProgress.getWorkflowStepID());
          tmpWorkflowProgress.setUserActorList(userActorList);
          result.set(i, tmpWorkflowProgress);
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Deletes all the progress that are belongs to the given track ID
   *
   * @param trackID The workflow track ID
   * @throws ApplicationException
   */
  public synchronized void deleteByTrackID(Integer trackID) throws ApplicationException {
    PreparedStatement preStat = null;
    StringBuffer sqlStat = new StringBuffer();
    synchronized (dbConn) {
      try {
        int updateCnt = 0;
        sqlStat.append("DELETE ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS ");
        sqlStat.append("WHERE  TRACK_ID=?  ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        setPrepareStatement(preStat, 1, trackID);
        updateCnt = preStat.executeUpdate();
        if (updateCnt == 0) {
          // throw new ApplicationException(ErrorConstant.DB_CONCURRENT_ERROR);
        }

      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_DELETE_ERROR, e);
      } finally {
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Gets a list of progress ID which SHOULD not be involved by the current login user after matching the staff hierarchy filtering.
   *
   * @return List of desired progress ID
   * @throws ApplicationException
   * @see com.dcivision.staff.bean.StaffRecord
   */
  public synchronized List getNotInvolvedWorkflowProgressIDList(AbstractSearchForm searchForm) throws ApplicationException {
    List result = new ArrayList();
    List possibleProgressList = new ArrayList();
    StringBuffer sqlStat = new StringBuffer();
//    PermissionManager pm = sessionContainer.getPermissionManager();
    Hashtable hashSubmitter = new Hashtable();
//    List userRolesList = getEffectiveUserRoles(searchForm);
//    List userGroupsList = getEffectiveUserGroups(searchForm);
    PreparedStatement preStat = null;
    ResultSet rs = null;
//    String tmpStr = "";

    // Get all possible involved tasks.
    //sqlStat.append("SELECT  DISTINCT WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.STATUS, WS.FILTER_BY \n");
    sqlStat.append("SELECT  DISTINCT WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WS.FILTER_BY \n");
    sqlStat.append("FROM    WORKFLOW_STEP WS, WORKFLOW_PROGRESS WP, MTM_WF_STEP_USER_ACTOR MWSUA \n");
    sqlStat.append("WHERE   WS.ID = WP.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WS.ID = MWSUA.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WP.CANCEL_FLAG = ? AND \n");
    sqlStat.append("        WP.COMPLETE_FLAG = ? AND \n");
    sqlStat.append("        (WP.STATUS = ? OR WP.STATUS = ?) AND \n");
    sqlStat.append("        WS.ACTION_TYPE <> ? AND \n");
    sqlStat.append("        WS.FILTER_BY IS NOT NULL AND \n");
    sqlStat.append("        WS.FILTER_BY > 0 AND \n");
    sqlStat.append("        MWSUA.ACTION_TYPE = ? \n");
    /*
    sqlStat.append("        MWSUA.ACTION_TYPE = ? AND \n");
    sqlStat.append("        (");

    for (int i = 0; userGroupsList != null && i < userGroupsList.size(); i++) {
      if (i != 0) {
        tmpStr += ", ";
      }
      UserGroup group = (UserGroup) userGroupsList.get(i);
      tmpStr += group.getID();
    }
    if (!Utility.isEmpty(tmpStr)) {
      sqlStat.append("         (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP + "' AND " + getInSQL("MWSUA.ACTOR_ID", tmpStr) + " ) \n");
    }

    tmpStr = "";

    for (int i = 0; userRolesList != null && i < userRolesList.size(); i++) {
      if (i != 0) {
        tmpStr += ", ";
      }
      UserRole role = (UserRole) userRolesList.get(i);
      tmpStr += role.getID();
    }
    if (!Utility.isEmpty(tmpStr)) {
      if (!Utility.isEmpty(userGroupsList)) {
        sqlStat.append(" OR ");
      }
      sqlStat.append("         (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE + "' AND " + getInSQL("MWSUA.ACTOR_ID", tmpStr) + " ) \n");
    }
    sqlStat.append("        ) ");
    */

    log.debug(sqlStat);

    synchronized (dbConn) {
      try {
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.FALSE);
        this.setPrepareStatement(preStat, 2, GlobalConstant.FALSE);
        this.setPrepareStatement(preStat, 3, WorkflowProgress.STATUS_PENDING);
        this.setPrepareStatement(preStat, 4, WorkflowProgress.STATUS_IN_PROGRESS);
        this.setPrepareStatement(preStat, 5, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
        this.setPrepareStatement(preStat, 6, MtmWorkflowStepUserActor.ACTION_TYPE_EXECUTION);

        rs = preStat.executeQuery();
        while (rs.next()) {
          // Progress ID, Workflow Step ID, Track ID.
          possibleProgressList.add(new Integer[] { this.getResultSetInteger(rs, "ID"), this.getResultSetInteger(rs, "WORKFLOW_STEP_ID"), this.getResultSetInteger(rs, "TRACK_ID"),
              this.getResultSetInteger(rs, "FILTER_BY") });
        }
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }

      // Within those possible involved tasks, find out which are definitely NOT
      // involved.
      try {
        sqlStat = new StringBuffer();
        for (int i = 0; i < possibleProgressList.size(); i++) {
          com.dcivision.staff.bean.StaffRecord submitter = null;
          Integer[] tmpAry = (Integer[]) possibleProgressList.get(i);
          if (hashSubmitter.get(tmpAry[2]) == null) {
            submitter = this.getStaffRecordForWorkflowTrackSubmitter(tmpAry[2]);
            if (submitter != null) {
              hashSubmitter.put(tmpAry[2], submitter);
            }
          } else {
            submitter = (com.dcivision.staff.bean.StaffRecord) hashSubmitter.get(tmpAry[2]);
          }

          String submitterLevelID = org.apache.commons.beanutils.BeanUtils.getProperty(submitter, "level" + tmpAry[3] + "ID");
          String currentUserLevelID = org.apache.commons.beanutils.BeanUtils.getProperty(this.sessionContainer.getStaffRecord(), "level" + tmpAry[3] + "ID");

          log.debug("submitterLevelID:" + submitterLevelID);
          log.debug("currentUserLevelID:" + currentUserLevelID);

          if (!Utility.isEmpty(submitterLevelID)) {
            if (!submitterLevelID.equals(currentUserLevelID)) {
              result.add(tmpAry[0]);
            }
          }
        }

        // get not involed workflow progress ID list of own groups and roles
        List tempList = getNotInvolvedOwnGroupsRolesWorkflowProgressIDList(searchForm);
        if (!Utility.isEmpty(tempList)) {
          result.addAll(tempList);
        }

        return (result);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      }
    }
  }

  /**
   * get the Progress List that have permission for Assign as runtime
   * @param searchForm
   * @return
   * @throws ApplicationException
   */
  public synchronized List getNotInvolvedWorkflowProgressIDforDynamic(AbstractSearchForm searchForm) throws ApplicationException {
    List result = new ArrayList();
    StringBuffer sqlStat = new StringBuffer();
    PreparedStatement preStat = null;
    ResultSet rs = null;
    sqlStat.append("SELECT  DISTINCT WP.ID  \n");
    sqlStat.append("FROM    WORKFLOW_STEP WS, WORKFLOW_PROGRESS WP, MTM_WF_STEP_USER_ACTOR MWSUA \n");
    sqlStat.append("WHERE   WS.ID = WP.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WS.ID = MWSUA.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WP.CANCEL_FLAG = ? AND \n");
    sqlStat.append("        WP.COMPLETE_FLAG = ? AND \n");
    sqlStat.append("        WP.STATUS = ? AND \n");
    sqlStat.append("        WS.ACTION_TYPE <> ? AND \n");
    sqlStat.append("        MWSUA.ACTION_TYPE = ? AND \n");
    sqlStat.append("        MWSUA.ACTOR_TYPE = ?  \n");
    synchronized (dbConn) {
      try {
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.FALSE);
        this.setPrepareStatement(preStat, 2, GlobalConstant.FALSE);
        this.setPrepareStatement(preStat, 3, WorkflowProgress.STATUS_PENDING);
        this.setPrepareStatement(preStat, 4, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
        this.setPrepareStatement(preStat, 5, MtmWorkflowStepUserActor.ACTION_TYPE_EXECUTION);
        this.setPrepareStatement(preStat, 6, MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN);
        rs = preStat.executeQuery();
        while (rs.next()) {
          result.add(this.getResultSetInteger(rs, "ID"));
        }
        return result;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  // Check filter rule.
  private AbstractQuery getSubQueryOfEqualFilterRuleCheck(Integer userRecordID) {

    // If the specified filter info (example: filter by role that submitor belongs to,
    // but sibmitor doesn't belongs to any role) of submitor is not exists, ignore filter check,
    // otherwise, check if current user is equal with the specified filter info.

    if (Utility.isEmpty(userRecordID)) {
      throw new NullPointerException("User record's id cann't be null!");
    }

    AbstractQuery subQuery = QueryUtil.createSubQuery();
    int queryIndex = 1;

    subQuery.append(
        "SELECT 'X' \n"
        );
    subQuery.append(
        "FROM \n" +
        "USER_RECORD SUB_URE \n" +
        "LEFT JOIN MTM_USER_RECORD_USER_GROUP SUB_MUREUG \n" +
        "ON SUB_MUREUG.USER_RECORD_ID = SUB_URE.ID \n" +
        "AND SUB_MUREUG.RECORD_STATUS = ? \n" +
        "LEFT JOIN MTM_USER_RECORD_USER_ROLE SUB_MUREURO \n" +
        "ON SUB_MUREURO.USER_RECORD_ID = SUB_URE.ID \n" +
        "AND SUB_MUREURO.RECORD_STATUS = ? \n" +
        "LEFT JOIN STAFF_RECORD SUB_SR \n" +
        "ON SUB_URE.USER_LINK_ID = SUB_SR.ID \n" +
        "AND SUB_SR.RECORD_STATUS = ? \n"
        );
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append(
        "WHERE \n"
        );
    subQuery.append(
        "SUB_URE.ID = ? \n"
    );
    subQuery.setParameter(queryIndex++, userRecordID);

    subQuery.append(
        "AND \n" +
        "( \n" +
        "   ( \n" +
        // Value is -1, filter by submitor.
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        "   WS.FILTER_BY = -1 \n" +
        "   AND \n" +
        "     ( \n" +
        "     NOT EXISTS \n" + // Ignore filter by submitor if submitor doesn't belong to any group(s).
        "       ( \n"
        );
    subQuery.subQuery(this.getSubQueryOfQueryGroupIDsOfSubmitter());
    subQuery.pack();
    queryIndex = subQuery.getParameterSize() + 1;

    subQuery.append(
        "       ) \n" +
        "     OR \n" + // Check if current user is in the same group with submitor.
        "     ( \n" +
        "     SUB_MUREUG.USER_GROUP_ID IN \n" +
        "       ( \n"
        );
    subQuery.subQuery(this.getSubQueryOfQueryGroupIDsOfSubmitter());
    subQuery.pack();
    queryIndex = subQuery.getParameterSize() + 1;

    subQuery.append(
        "       ) \n" +
        "     ) \n" +
        "     ) \n" +
        "   ) \n"
        );

    subQuery.append(
        // Value is -2, filter by submitor's role.
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        "   OR \n" +
        "   ( \n" +
        "   WS.FILTER_BY = -2 \n" +
        "   AND \n" +
        "     ( \n" +
        "     NOT EXISTS \n" +
        "       ( \n"
        );
    subQuery.subQuery(this.getSubQueryOfQueryRoleIDsOfSubmitter());
    subQuery.pack();
    queryIndex = subQuery.getParameterSize() + 1;

    subQuery.append(
        "       ) \n" +
        "     OR \n" +
        "     ( \n" +
        "     SUB_MUREURO.USER_ROLE_ID IN \n" +
        "       ( \n"
        );
    subQuery.subQuery(this.getSubQueryOfQueryRoleIDsOfSubmitter());
    subQuery.pack();
    queryIndex = subQuery.getParameterSize() + 1;

    subQuery.append(
        "       ) \n" +
        "     ) \n" +
        "     ) \n" +
        "   ) \n"
        );

    // Value is larger than zero, filter by submitor's staff info.
    // Construct the query by the total level count.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    int totalLevel = 10; // NOTE: Change this value if the staff's level architecture is changed.
    for (int level = 1; level <= totalLevel; level++) {
      subQuery.append(
          "   OR \n" +
          "   ( \n" +
          "   WS.FILTER_BY = " + level + " \n" +
          "   AND \n" +
          "     ( \n" +
          "     NOT EXISTS \n" +
          "       ( \n"
          );
      subQuery.subQuery(this.getSubQueryOfQueryStaffLevelInfoOfSubmitter(level));
      subQuery.pack();
      queryIndex = subQuery.getParameterSize() + 1;

      subQuery.append(
          "       ) \n" +
          "     OR \n" +
          "     ( \n" +
          "     SUB_SR.LEVEL_" + level + "_ID IN \n" +
          "       ( \n"
          );

      subQuery.subQuery(this.getSubQueryOfQueryStaffLevelInfoOfSubmitter(level));
      subQuery.pack();
      queryIndex = subQuery.getParameterSize() + 1;

      subQuery.append(
          "       ) \n" +
          "     ) \n" +
          "     ) \n" +
          "   ) \n"
          );
    }

    subQuery.append(
        ") \n"
        );

    return (subQuery);
  }

  public AbstractQuery getSubQueryOfDynamicAssignedStepCheck() {
    AbstractQuery subQuery = QueryUtil.createSubQuery();
    int queryIndex = 1;

    subQuery.append(
        "SELECT 'X' \n"
        );
    subQuery.append(
        "FROM \n" +
        "MTM_WF_STEP_USER_ACTOR SUB_MWSUA \n"
        );
    subQuery.append(
        "WHERE \n"
        );
    subQuery.append(
        "SUB_MWSUA.WORKFLOW_STEP_ID = WS.ID \n" +
        "AND SUB_MWSUA.ACTOR_TYPE = ? \n" +
        "AND SUB_MWSUA.RECORD_STATUS = ? \n" +
        "AND SUB_MWSUA.ACTION_TYPE = ? \n"
        );

    subQuery.setParameter(queryIndex++, MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, MtmWorkflowStepUserActor.ACTION_TYPE_EXECUTION);

    return (subQuery);
  }

  public AbstractQuery getNotInvolvedWorkflowProgressIDforDynamicStr(AbstractSearchForm searchForm){
    AbstractQuery subQuery = new SubQuery();

    StringBuffer sqlStat = new StringBuffer();
    sqlStat.append("SELECT  'X'  \n");//DISTINCT WP.ID
    sqlStat.append("FROM    WORKFLOW_STEP WS,  MTM_WF_STEP_USER_ACTOR MWSUA \n");//WORKFLOW_PROGRESS WP,
    sqlStat.append("WHERE   WS.ID = WP.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WS.ID = MWSUA.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WP.CANCEL_FLAG = ? AND \n");
    sqlStat.append("        WP.COMPLETE_FLAG = ? AND \n");
    sqlStat.append("        WP.STATUS = ? AND \n");
    sqlStat.append("        WS.ACTION_TYPE <> ? AND \n");
    sqlStat.append("        MWSUA.ACTION_TYPE = ? AND \n");
    sqlStat.append("        MWSUA.ACTOR_TYPE = ?  \n");

    subQuery.append(sqlStat.toString());
    int i=1;
    subQuery.setParameter(i++, GlobalConstant.FALSE);
    subQuery.setParameter(i++, GlobalConstant.FALSE);
    subQuery.setParameter(i++, WorkflowProgress.STATUS_PENDING);
    subQuery.setParameter(i++, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
    subQuery.setParameter(i++, MtmWorkflowStepUserActor.ACTION_TYPE_EXECUTION);
    subQuery.setParameter(i++, MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN);
    return subQuery;
  }
  /**
   * Gets a list of progress ID which SHOULD not be involved by the current login user's after matching the user's group/role
   *
   * @return List of desired progress ID
   * @throws ApplicationException
   */
  private synchronized List getNotInvolvedOwnGroupsRolesWorkflowProgressIDList(AbstractSearchForm searchForm) throws ApplicationException {
    List possibleProgressList = new ArrayList();
    List result = new ArrayList();
    StringBuffer sqlStat = new StringBuffer();
    List userRolesList = getEffectiveUserRoles(searchForm);
    List userGroupsList = getEffectiveUserGroups(searchForm);
    PreparedStatement preStat = null;
    ResultSet rs = null;
    //String tmpStr = "";

    // Get all possible involved tasks.
    sqlStat.append("SELECT  DISTINCT WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.STATUS, WS.FILTER_BY \n");
    sqlStat.append("FROM    WORKFLOW_STEP WS, WORKFLOW_PROGRESS WP, MTM_WF_STEP_USER_ACTOR MWSUA \n");
    sqlStat.append("WHERE   WS.ID = WP.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WS.ID = MWSUA.WORKFLOW_STEP_ID AND \n");
    sqlStat.append("        WP.CANCEL_FLAG = ? AND \n");
    sqlStat.append("        WP.COMPLETE_FLAG = ? AND \n");
    sqlStat.append("        (WP.STATUS = ? OR WP.STATUS = ?) AND \n");
    sqlStat.append("        WS.ACTION_TYPE <> ? AND \n");
    sqlStat.append("        WS.FILTER_BY IS NOT NULL AND \n");
    sqlStat.append("        WS.FILTER_BY < 0 AND \n");
    sqlStat.append("        MWSUA.ACTION_TYPE = ? "); /* AND \n");
    sqlStat.append("        (");

    for (int i = 0; userGroupsList != null && i < userGroupsList.size(); i++) {
      if (i != 0) {
        tmpStr += ", ";
      }
      UserGroup group = (UserGroup) userGroupsList.get(i);
      tmpStr += group.getID();
    }
    if (!Utility.isEmpty(tmpStr)) {
      sqlStat.append("         (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP + "' AND " + getInSQL("MWSUA.ACTOR_ID", tmpStr) + " ) \n");
    }

    tmpStr = "";

    for (int i = 0; userRolesList != null && i < userRolesList.size(); i++) {
      if (i != 0) {
        tmpStr += ", ";
      }
      UserRole role = (UserRole) userRolesList.get(i);
      tmpStr += role.getID();
    }
    if (!Utility.isEmpty(tmpStr)) {
      if (!Utility.isEmpty(userGroupsList)) {
        sqlStat.append(" OR ");
      }
      sqlStat.append("         (MWSUA.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE + "' AND " + getInSQL("MWSUA.ACTOR_ID", tmpStr) + " ) \n");
    }
    sqlStat.append("        ) "); */

    log.debug(sqlStat);

    synchronized (dbConn) {
      try {
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.FALSE);
        this.setPrepareStatement(preStat, 2, GlobalConstant.FALSE);
        this.setPrepareStatement(preStat, 3, WorkflowProgress.STATUS_PENDING);
        this.setPrepareStatement(preStat, 4, WorkflowProgress.STATUS_IN_PROGRESS);
        this.setPrepareStatement(preStat, 5, WorkflowStep.ACTION_TYPE_SYSTEM_AUTO);
        this.setPrepareStatement(preStat, 6, MtmWorkflowStepUserActor.ACTION_TYPE_EXECUTION);

        rs = preStat.executeQuery();
        while (rs.next()) {
          // Progress ID, Workflow Step ID, Track ID, Filterby
          possibleProgressList.add(new Integer[] { this.getResultSetInteger(rs, "ID"), this.getResultSetInteger(rs, "WORKFLOW_STEP_ID"), this.getResultSetInteger(rs, "TRACK_ID"),
              this.getResultSetInteger(rs, "FILTER_BY") });
          // result.add(this.getResultSetInteger(rs, "ID"));
        }
        // return result;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }

      // Within those possible involved tasks, find out which are definitely NOT
      // involved.
      try {
        sqlStat = new StringBuffer();
        for (int i = 0; i < possibleProgressList.size(); i++) {
          Integer[] tmpAry = (Integer[]) possibleProgressList.get(i);
          Integer progressID = tmpAry[0];
          Integer stepID = tmpAry[1];
          Integer trackID = tmpAry[2];
          Integer filterBy = tmpAry[3];
          log.debug("progressID = " + progressID);
          log.debug("stepID = " + stepID);
          log.debug("trackID = " + trackID);
          log.debug("filterBy = " + filterBy);
          boolean matched = false;
          // if filter by group
          if (filterBy.intValue() == -1) {
            UserGroupDAObject userGroupDAO = new UserGroupDAObject(this.sessionContainer, this.dbConn);
            List submitterGroupList = userGroupDAO.getListByUserRecordIDGroupType(getUserIDForWorkflowTrackSubmitter(trackID), UserGroup.GROUP_TYPE_PUBLIC);
            for (int j = 0; j < userGroupsList.size(); j++) {
              UserGroup group = (UserGroup) userGroupsList.get(j);
              Integer groupID = group.getID();
              // loop through submitter's group to find matching id
              for (int k = 0; k < submitterGroupList.size(); k++) {
                UserGroup group2 = (UserGroup) submitterGroupList.get(k);
                if (groupID.intValue() == group2.getID().intValue()) {
                  matched = true;
                  break;
                }
              }
            }
          }// else if filter by role
          else if (filterBy.intValue() == -2) {
            UserRoleDAObject userRoleDAO = new UserRoleDAObject(this.sessionContainer, this.dbConn);
            List submitterRoleList = userRoleDAO.getListByUserRecordID(getUserIDForWorkflowTrackSubmitter(trackID));
            for (int j = 0; j < userRolesList.size(); j++) {
              UserRole role = (UserRole) userRolesList.get(j);
              Integer roleID = role.getID();
              // loop through submitter's role to find matching id
              for (int k = 0; k < submitterRoleList.size(); k++) {
                UserRole role2 = (UserRole) submitterRoleList.get(k);
                if (roleID.intValue() == role2.getID().intValue()) {
                  matched = true;
                  break;
                }
              }
            }
          }
          // end if
          if (!matched) {
            result.add(tmpAry[0]);
          }
        }

        // get Deny progress ID List
        List denyProgressIDList = this.getDenyProgressIDList();
        if (!Utility.isEmpty(denyProgressIDList)) {
          result.addAll(denyProgressIDList);
        }

        return (result);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      }

    }
  }

  /**
   * Gets a list of track that related to the specified document reference number.
   *
   * @param documentReferenceNumber The document's reference number
   * @return List of desired track ID
   * @throws ApplicationException
   * @see com.dcivision.dms.bean.DmsDocument
   */
  private synchronized List getTrackIDListByDocumentReferenceNumber(String documentReferenceNumber) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List result = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.TRACK_ID ");
        sqlStat.append("FROM MTM_WF_PROGRESS_SYSTEM_OBJECT A, DMS_DOCUMENT B ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? AND ");
        // sqlStat.append(" B.RECORD_STATUS = ? AND ");
        sqlStat.append("       A.OBJECT_ID = B.ID AND ");
        sqlStat.append("       B.REFERENCE_NO = ? ");

        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        // this.setPrepareStatement(preStat, 2,GlobalConstant.RECORD_STATUS_PENDING);
        this.setPrepareStatement(preStat, 2, documentReferenceNumber);

        rs = preStat.executeQuery();

        while (rs.next()) {
          result.add(getResultSetInteger(rs, "TRACK_ID"));
        }
        return (result);
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }

  }

//sliever.hu.add.start
  private synchronized List getTrackIDListByDocumentReferenceNumber(String documentReferenceNumber,boolean select) throws ApplicationException {
    if(select){
      return this.getTrackIDListByDocumentReferenceNumber(documentReferenceNumber);
    }else{
      PreparedStatement preStat = null;
      ResultSet rs = null;
      StringBuffer sqlStat = new StringBuffer();
      List result = new ArrayList();
      String ReferenceNumber=documentReferenceNumber;
      synchronized (dbConn) {
        try {
          sqlStat.append("SELECT A.TRACK_ID ");
          sqlStat.append("FROM MTM_WF_PROGRESS_SYSTEM_OBJECT A, DMS_DOCUMENT B ");
          sqlStat.append("WHERE  A.RECORD_STATUS = ? AND ");
          sqlStat.append(" A.OBJECT_ID = B.ID AND ");
          sqlStat.append(" (B.REFERENCE_NO LIKE '%"+ReferenceNumber+"%' OR ");
          sqlStat.append(" B.REFERENCE_NO LIKE '%"+ReferenceNumber+"' OR ");
          sqlStat.append(" B.REFERENCE_NO  LIKE '"+ReferenceNumber+ "%')");
          preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
          this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);

          rs = preStat.executeQuery();

          while (rs.next()) {
            result.add(getResultSetInteger(rs, "TRACK_ID"));
          }
          return (result);
        } catch (ApplicationException appEx) {
          throw appEx;
        } catch (SQLException sqle) {
          log.error(sqle, sqle);
          throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
        } catch (Exception e) {
          log.error(e, e);
          throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
        } finally {
          try {
            rs.close();
          } catch (Exception ignore) {
          } finally {
            rs = null;
          }
          try {
            preStat.close();
          } catch (Exception ignore) {
          } finally {
            preStat = null;
          }
        }
      }
    }
   }
  //sliever.hu.add.end

  private synchronized String getTrackIDsByRelatedDMSObject(String relatedObject,String recordStatus) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    AbstractQuery subQuery = null;

    StringBuffer wfProgressIDs = new StringBuffer("-1");

    synchronized (dbConn) {
      try {
        subQuery = this.getTrackIDsSQLByRelatedDMSObject(relatedObject, recordStatus);
        subQuery.pack();
        preStat = dbConn.prepareStatement(subQuery.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPreparedStatement(preStat, 1, subQuery.getAllParameters());

        rs = preStat.executeQuery();

        while (rs.next()) {
          wfProgressIDs.append(", " + this.getResultSetString(rs, "ID"));
        }

        return (wfProgressIDs.toString());
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  private synchronized String getTrackIDsByRelatedFormObject(String relatedObject,String recordStatus) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    AbstractQuery subQuery = null;

    StringBuffer wfProgressIDs = new StringBuffer("-1");

    synchronized (dbConn) {
      try {
        subQuery = this.getTrackIDsSQLByRelatedFormObject(relatedObject, recordStatus);
        subQuery.pack();
        preStat = dbConn.prepareStatement(subQuery.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPreparedStatement(preStat, 1, subQuery.getAllParameters());

        rs = preStat.executeQuery();

        while (rs.next()) {
          wfProgressIDs.append(", " + this.getResultSetString(rs, "ID"));
        }

        return (wfProgressIDs.toString());
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  private synchronized String getTrackIDsByRelatedInterruptObject(String relatedObject,String recordStatus) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    AbstractQuery subQuery = null;

    StringBuffer wfProgressIDs = new StringBuffer("-1");

    synchronized (dbConn) {
      try {
        subQuery = this.getTrackIDsSQLByRelatedInterruptObject(relatedObject, recordStatus);
        subQuery.pack();
        preStat = dbConn.prepareStatement(subQuery.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPreparedStatement(preStat, 1, subQuery.getAllParameters());

        rs = preStat.executeQuery();

        while (rs.next()) {
          wfProgressIDs.append(", " + this.getResultSetString(rs, "ID"));
        }

        return (wfProgressIDs.toString());
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * get the trackID by related object
   *
   * @param referenceNo
   * @return
   * @throws ApplicationException
   */
  private synchronized String getTrackIDsByRelatedObject(String relatedObject,String recordStatus) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    AbstractQuery subQuery = null;

    StringBuffer wfProgressIDs = new StringBuffer("-1");

    synchronized (dbConn) {
      try {
        subQuery = this.getTrackIDsSQLByRelatedObject(relatedObject, recordStatus);
        subQuery.pack();
        preStat = dbConn.prepareStatement(subQuery.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPreparedStatement(preStat, 1, subQuery.getAllParameters());

        rs = preStat.executeQuery();

        while (rs.next()) {
          wfProgressIDs.append(", " + this.getResultSetString(rs, "ID"));
        }

        return (wfProgressIDs.toString());
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  private AbstractQuery getTrackIDsSQLByRelatedDMSObject(String relatedDMSObject, String recordStatus) {
    AbstractQuery subQuery = new SubQuery();
    StringBuffer sqlStat = new StringBuffer();
    sqlStat.append("SELECT C.ID ");//WORKFLOW_PROGRESS_ID
    sqlStat.append("FROM DMS_DOCUMENT A, MTM_WF_PROGRESS_SYSTEM_OBJECT B,WORKFLOW_PROGRESS C ");
    sqlStat.append("WHERE  ").append(this.getSearchColumn("DOCUMENT_NAME")).append(" LIKE  ?  AND  ");
    sqlStat.append(" A.ID = B.OBJECT_ID AND ");
    sqlStat.append(" B.BEAN_CLASS_NAME = 'com.dcivision.dms.bean.DmsDocument' AND ");
    sqlStat.append(" B.TRACK_ID = C.TRACK_ID ");
    if(recordStatus!=null) {
      sqlStat.append(" AND B.RECORD_STATUS = ? ");
    }
    log.info(sqlStat);
    subQuery.append(sqlStat.toString());

    // ------------------------------------------------------------Fill Parameters for This SubQuery.

    int i=1;
    String referenceNoStr = this.getFormattedKeyword(relatedDMSObject, "LIKE");
    subQuery.setParameter(i++, referenceNoStr);
    if(recordStatus!=null){
      subQuery.setParameter(i++, recordStatus);
    }
    subQuery.pack();
    return subQuery;
  }

  private AbstractQuery getTrackIDsSQLByRelatedFormObject(String relatedFormObject, String recordStatus) {
    AbstractQuery subQuery = new SubQuery();
    StringBuffer sqlStat = new StringBuffer();
    sqlStat.append("SELECT C.ID ");//WORKFLOW_PROGRESS_ID
    sqlStat.append("FROM FORM_RECORD A, MTM_WF_PROGRESS_SYSTEM_OBJECT B, WORKFLOW_PROGRESS C,FORM_SUBMISSION D,FORM_ELEMENT E ");
    sqlStat.append("WHERE  ");
    sqlStat.append(" A.ID = D.FORM_RECORD_ID AND ");
    sqlStat.append(" D.ID = B.OBJECT_ID AND ");
    sqlStat.append(" B.BEAN_CLASS_NAME = 'com.dcivision.form.bean.FormSubmission' AND ");
    sqlStat.append(" B.TRACK_ID = C.TRACK_ID AND ");
    sqlStat.append(" (A.DISPLAY_ELEMENT_ID = 0 AND A.TITLE LIKE ?) ");
    if(recordStatus!=null) {
      sqlStat.append(" AND B.RECORD_STATUS = ? ");
    }
    log.info(sqlStat);
    subQuery.append(sqlStat.toString());

    // ------------------------------------------------------------Fill Parameters for This SubQuery.

    int i=1;
    String relatedItemStr = this.getFormattedKeyword(relatedFormObject, "LIKE");
    subQuery.setParameter(i++, relatedItemStr);
    if(recordStatus!=null){
      subQuery.setParameter(i++, recordStatus);
    }

    subQuery.pack();
    return subQuery;
  }

  private AbstractQuery getTrackIDsSQLByRelatedInterruptObject(String relatedInterruptObject, String recordStatus) {
    AbstractQuery subQuery = new SubQuery();
    StringBuffer sqlStat = new StringBuffer();
    sqlStat.append("SELECT DISTINCT D.PARENT_WORKFLOW_PROGRESS_ID ");
    sqlStat.append("FROM WORKFLOW_RECORD A, WORKFLOW_STEP B,");
    sqlStat.append("WORKFLOW_PROGRESS C,MTM_WF_CHILD_PARENT_PROGRESS D ");
    sqlStat.append("WHERE  (").append(this.getSearchColumn("WORKFLOW_CODE")).append(" LIKE  ?  AND  ");
    sqlStat.append(" A.WORKFLOW_CATEGORY_ID = "+SystemWorkflowConstant.SUB_WORKFLOW_INTERRUPT+" AND ");
    sqlStat.append(" B.WORKFLOW_RECORD_ID = A.ID AND ");
    sqlStat.append(" C.WORKFLOW_STEP_ID = B.ID AND ");
    sqlStat.append(" C.TRACK_ID = D.SUBWORKFLOW_TRACK_ID");
    sqlStat.append(" )");
    log.info(sqlStat);
    subQuery.append(sqlStat.toString());

    // ------------------------------------------------------------Fill Parameters for This SubQuery.

    int i=1;
    String referenceNoStr = this.getFormattedKeyword(relatedInterruptObject, "LIKE");
    subQuery.setParameter(i++, referenceNoStr);
    subQuery.pack();
    return subQuery;
  }

  private AbstractQuery getTrackIDsSQLByRelatedTriggerSubWorkflowObject(
      String relatedInterruptObject, String recordStatus) {
    AbstractQuery subQuery = new SubQuery();
    StringBuffer sqlStat = new StringBuffer();
    sqlStat.append("SELECT C.ID ");
    sqlStat.append("FROM  WORKFLOW_STEP_PARAMETER_VALUE A, WORKFLOW_STEP B, WORKFLOW_PROGRESS C ");
    sqlStat.append("WHERE  (").append(this.getSearchColumn("PARAMETER_VALUE")).append(" LIKE  ?  AND  ");
    sqlStat.append(" C.WORKFLOW_STEP_ID = B.ID ");
    sqlStat.append(" AND A.PARAMETER_NAME = 'workflow.label.workflow_code' ");
    sqlStat.append(" AND A.WORKFLOW_STEP_ID = C.WORKFLOW_STEP_ID");
    sqlStat.append(" AND C.RECORD_STATUS = ? )");
    log.info(sqlStat);
    subQuery.append(sqlStat.toString());

    // ------------------------------------------------------------Fill Parameters for This SubQuery.

    int i=1;
    String referenceNoStr = this.getFormattedKeyword(relatedInterruptObject, "LIKE");
    subQuery.setParameter(i++, referenceNoStr);
    subQuery.setParameter(i++, recordStatus);
    subQuery.pack();
    return subQuery;
  }

  private AbstractQuery getTrackIDsSQLByRelatedSubWorkflowTrackIDObject(
      Integer relatedInterruptObject, String recordStatus) {
    AbstractQuery subQuery = new SubQuery();
    StringBuffer sqlStat = new StringBuffer();
    sqlStat.append(" SELECT A.PARENT_WORKFLOW_PROGRESS_ID ");
    sqlStat.append(" FROM MTM_WF_CHILD_PARENT_PROGRESS A");
    sqlStat.append(" WHERE (A.SUBWORKFLOW_TRACK_ID = ? AND A.RECORD_STATUS = ?");
    sqlStat.append(" )");
    log.info(sqlStat);
    subQuery.append(sqlStat.toString());

    // ------------------------------------------------------------Fill Parameters for This SubQuery.

    int i=1;
    subQuery.setParameter(i++, relatedInterruptObject);
    subQuery.setParameter(i++, recordStatus);
    subQuery.pack();
    return subQuery;
  }

  //ADD BY TC FOR TEST
  private AbstractQuery getTrackIDsSQLByRelatedObject(String relatedObject, String recordStatus){
    //SqlstrAndParameters sqlStrandPara = new SqlstrAndParameters();
    AbstractQuery subQuery = new SubQuery();
    // Related to DMS.
    subQuery.subQuery(this.getTrackIDsSQLByRelatedDMSObject(relatedObject, recordStatus));
    subQuery.append("\tUNION\t");
    // Related to Form.
    subQuery.subQuery(this.getTrackIDsSQLByRelatedFormObject(relatedObject, recordStatus));
    subQuery.append("\tUNION\t");
    // Related to Interrupt.
    subQuery.subQuery(this.getTrackIDsSQLByRelatedInterruptObject(relatedObject, recordStatus));
    subQuery.append("\tUNION\t");

    subQuery.subQuery(this.getTrackIDsSQLByRelatedTriggerSubWorkflowObject(
        relatedObject, GlobalConstant.RECORD_STATUS_ACTIVE));

    Integer subWorkflowTrackID = TextUtility.parseIntegerObj(relatedObject);
    if (!Utility.isEmpty(subWorkflowTrackID)) {
      subQuery.append("\tUNION\t");
      subQuery.subQuery(this.getTrackIDsSQLByRelatedSubWorkflowTrackIDObject(
          subWorkflowTrackID, GlobalConstant.RECORD_STATUS_ACTIVE));
    }
    log.info(subQuery.toString());

    subQuery.pack();

    return subQuery;
  }

  /**
   * Gets list of progress id that is assigned to submitter's report to, but the submitter do not have proper report to relationship
   *
   * @return List of desired progress
   * @throws ApplicationException
   */
  public synchronized List getProgressIDListForFailedMentor() throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();
    synchronized (dbConn) {
      try {
        sqlStat.append(" SELECT PX.*");
        sqlStat.append(" FROM WORKFLOW_PROGRESS P1, MTM_WF_PROGRESS_USER_RECORD MPU, USER_RECORD U, STAFF_RECORD S,");
        sqlStat.append(" WORKFLOW_PROGRESS PX, WORKFLOW_STEP SX, MTM_WF_STEP_USER_ACTOR AX");
        sqlStat.append(" WHERE P1.SEQ_NO=1");
        sqlStat.append(" AND P1.ID=MPU.WORKFLOW_PROGRESS_ID");
        sqlStat.append(" AND U.ID=MPU.USER_RECORD_ID");
        sqlStat.append(" AND U.USER_LINK_ID=S.ID");
        sqlStat.append(" AND S.REPORT_TO_STAFF_RECORD_ID IS NULL");
        sqlStat.append(" AND P1.TRACK_ID=PX.TRACK_ID");
        sqlStat.append(" AND PX.WORKFLOW_STEP_ID=SX.ID");
        sqlStat.append(" AND AX.WORKFLOW_STEP_ID=SX.ID");
        sqlStat.append(" AND (PX.STATUS=? OR PX.STATUS=?)");
        sqlStat.append(" AND AX.ACTOR_TYPE=?");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, WorkflowProgress.STATUS_PENDING);
        setPrepareStatement(preStat, 2, WorkflowProgress.STATUS_IN_PROGRESS);
        setPrepareStatement(preStat, 3, MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }

  /**
   * Gets list of progress id that is assigned to previous task action's report to, but the previous action taker do not have proper report to relationship
   *
   * @return List of desired progress
   * @throws ApplicationException
   */
  public synchronized List getProgressIDListForFailedReportToOfPreviousTask() throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT C.ID ");
        sqlStat.append("FROM WORKFLOW_PROGRESS A, MTM_WF_PROGRESS_USER_RECORD B, WORKFLOW_PROGRESS C, MTM_WF_PROGRESS_WF_PROGRESS D, USER_RECORD E, STAFF_RECORD F, MTM_WF_STEP_USER_ACTOR G ");
        sqlStat.append("WHERE A.ID = B.WORKFLOW_PROGRESS_ID AND ");
        sqlStat.append("      A.ID = D.PARENT_PROGRESS_ID AND ");
        sqlStat.append("      C.ID = D.CHILD_PROGRESS_ID AND ");
        sqlStat.append("      E.ID = B.USER_RECORD_ID AND ");
        sqlStat.append("      F.ID = E.USER_LINK_ID AND ");
        sqlStat.append("      C.WORKFLOW_STEP_ID = G.WORKFLOW_STEP_ID AND ");
        sqlStat.append("      G.ACTOR_TYPE = ? AND ");
        sqlStat.append("      F.REPORT_TO_STAFF_RECORD_ID IS NULL ");
        sqlStat.append("      AND (C.STATUS = ? OR C.STATUS = ?) ");

        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER);
        setPrepareStatement(preStat, 2, WorkflowProgress.STATUS_PENDING);
        setPrepareStatement(preStat, 3, WorkflowProgress.STATUS_IN_PROGRESS);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }

  /**
   * get tacke ID list for previous task actor taker.
   *
   * @param userRecordID
   * @return
   * @throws ApplicationException
   */

/*    public synchronized List getTrackIDListForPreviousTaskActorTaker(Integer userRecordID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT C.TRACK_ID ");
        sqlStat.append("FROM WORKFLOW_PROGRESS A, MTM_WF_PROGRESS_USER_RECORD B,WORKFLOW_PROGRESS C, MTM_WF_PROGRESS_WF_PROGRESS D, MTM_WF_STEP_USER_ACTOR E ");
        sqlStat.append("WHERE A.ID = B.WORKFLOW_PROGRESS_ID AND ");
        sqlStat.append(" A.ID = D.PARENT_PROGRESS_ID AND ");
        sqlStat.append(" C.ID = D.CHILD_PROGRESS_ID AND ");
        sqlStat.append(" C.WORKFLOW_STEP_ID = E.WORKFLOW_STEP_ID AND ");
        sqlStat.append(" E.ACTOR_TYPE = ? AND ");
        sqlStat.append(" B.USER_RECORD_ID = ? ");
        sqlStat.append(" AND (C.STATUS = ? OR C.STATUS = ? OR C.STATUS = ?) ");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER);
        setPrepareStatement(preStat, 2, userRecordID);
        setPrepareStatement(preStat, 3, WorkflowProgress.STATUS_PENDING);
        setPrepareStatement(preStat, 4, WorkflowProgress.STATUS_IN_PROGRESS);
        setPrepareStatement(preStat, 5, WorkflowProgress.STATUS_LOCK);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "TRACK_ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }*/

  /**
   * Gets a list of task that are assigned to the given user record as if he/she is the original submitter or his/her supervisor
   *
   * @param actorType Subimtter or his/her supervisor
   * @param userRecordID The current user record id
   * @return List of desired task (WorkflowProgress) ID
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.MtmWorkflowStepUserActor
   */
  public synchronized List getProgressIDListBySubmitterOrReportTo(String actorType, Integer userRecordID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT WP.ID\n");
        sqlStat.append("FROM WORKFLOW_RECORD R, WORKFLOW_STEP S, WORKFLOW_PROGRESS WP, MTM_WF_STEP_USER_ACTOR SUA,\n");
        sqlStat.append("  WORKFLOW_PROGRESS WPX, MTM_WF_PROGRESS_USER_RECORD PUR,\n");
        sqlStat.append("  USER_RECORD U LEFT JOIN STAFF_RECORD STF ON U.USER_LINK_ID=STF.ID\n");
        sqlStat.append("  LEFT JOIN USER_RECORD U2 ON STF.REPORT_TO_STAFF_RECORD_ID=U2.USER_LINK_ID\n");
        sqlStat.append("WHERE R.ID=S.WORKFLOW_RECORD_ID\n");
        sqlStat.append("  AND S.ID=WP.WORKFLOW_STEP_ID\n");
        sqlStat.append("  AND SUA.WORKFLOW_STEP_ID=WP.WORKFLOW_STEP_ID\n");
        sqlStat.append("  AND (WP.STATUS = ? OR WP.STATUS = ? OR WP.STATUS = ?) \n");
        sqlStat.append("  AND WP.COMPLETE_FLAG = ? \n");
        sqlStat.append("  AND WP.TRACK_ID=WPX.TRACK_ID\n");
        sqlStat.append("  AND WPX.ID=PUR.WORKFLOW_PROGRESS_ID\n");
        sqlStat.append("  AND PUR.USER_RECORD_ID=U.ID\n");
        sqlStat.append("  AND WPX.SEQ_NO=1\n");
        sqlStat.append("  AND SUA.ACTOR_TYPE=? \n");
        if (MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER.equals(actorType)) {
          sqlStat.append("  AND U.ID=?\n");
        } else {
          // if(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO.equals(actorType)){
          sqlStat.append("  AND U2.ID=?\n");
        }
        preStat = dbConn.prepareStatement(sqlStat.toString());
        int i = 1;
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_IN_PROGRESS);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_LOCK);
        setPrepareStatement(preStat, i++, GlobalConstant.FALSE);
        setPrepareStatement(preStat, i++, actorType);
        setPrepareStatement(preStat, i++, userRecordID);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }

  // This sub query purpose to found out all the role id(s) of current progress's submitor.
  private AbstractQuery getSubQueryOfQueryRoleIDsOfSubmitter() {
    AbstractQuery subQuery = QueryUtil.createSubQuery();
    int queryIndex = 1;

    subQuery.append(
        "SELECT \n" +
        "S_SUB_MUREURO.USER_ROLE_ID \n"
        );

    subQuery.append(
        "FROM \n" +
        "WORKFLOW_PROGRESS S_SUB_WP \n" +
        "JOIN WORKFLOW_STEP S_SUB_WS \n" +
        "ON S_SUB_WP.WORKFLOW_STEP_ID = S_SUB_WS.ID \n" +
        "AND S_SUB_WS.RECORD_STATUS = ? \n" +
        "AND S_SUB_WS.STEP_SEQ = ? \n" + // And is start step.
        "JOIN MTM_WF_PROGRESS_USER_RECORD S_SUB_MWPUR \n" +
        "ON S_SUB_MWPUR.WORKFLOW_PROGRESS_ID = S_SUB_WP.ID \n" +
        "AND S_SUB_MWPUR.RECORD_STATUS = ? \n" +
        "LEFT JOIN USER_RECORD S_SUB_URS \n" +
        "ON S_SUB_MWPUR.USER_RECORD_ID = S_SUB_URS.ID \n" +
        "AND S_SUB_URS.RECORD_STATUS = ? \n" +
        "LEFT JOIN MTM_USER_RECORD_USER_ROLE S_SUB_MUREURO \n" +
        "ON S_SUB_MUREURO.USER_RECORD_ID = S_SUB_URS.ID \n" +
        "AND S_SUB_MUREURO.RECORD_STATUS = ? \n"
        );

    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, WorkflowStep.START_STEP_SEQ_NO);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append(
        "WHERE \n" +
        "S_SUB_WP.RECORD_STATUS = ? \n" +
        "AND S_SUB_WP.TRACK_ID = WP.TRACK_ID \n" // The same track.
        );
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append(
        "AND S_SUB_MUREURO.USER_ROLE_ID IS NOT NULL \n" // Must exists.
        );

    subQuery.append( // Complete actor.
        "AND S_SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND S_SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND S_SUB_MWPUR.WORKFLOW_ACTION <> ? \n"
        );

    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_PENDING);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_IN_PROGRESS);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_LOCK);

    return (subQuery);
  }

  // This sub query purpose to found out all the group id(s) of current progress's submitor.
  private AbstractQuery getSubQueryOfQueryGroupIDsOfSubmitter() {
    AbstractQuery subQuery = QueryUtil.createSubQuery();
    int queryIndex = 1;

    subQuery.append(
        "SELECT \n" +
        "S_SUB_MUREUG.USER_GROUP_ID \n"
        );

    subQuery.append(
        "FROM \n" +
        "WORKFLOW_PROGRESS S_SUB_WP \n" +
        "JOIN WORKFLOW_STEP S_SUB_WS \n" +
        "ON S_SUB_WP.WORKFLOW_STEP_ID = S_SUB_WS.ID \n" +
        "AND S_SUB_WS.RECORD_STATUS = ? \n" +
        "AND S_SUB_WS.STEP_SEQ = ? \n" + // And is start step.
        "JOIN MTM_WF_PROGRESS_USER_RECORD S_SUB_MWPUR \n" +
        "ON S_SUB_MWPUR.WORKFLOW_PROGRESS_ID = S_SUB_WP.ID \n" +
        "AND S_SUB_MWPUR.RECORD_STATUS = ? \n" +
        "LEFT JOIN USER_RECORD S_SUB_URS \n" +
        "ON S_SUB_MWPUR.USER_RECORD_ID = S_SUB_URS.ID \n" +
        "AND S_SUB_URS.RECORD_STATUS = ? \n" +
        "LEFT JOIN MTM_USER_RECORD_USER_GROUP S_SUB_MUREUG \n" +
        "ON S_SUB_MUREUG.USER_RECORD_ID = S_SUB_URS.ID \n" +
        "AND S_SUB_MUREUG.RECORD_STATUS = ? \n"
        );

    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, WorkflowStep.START_STEP_SEQ_NO);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append(
        "WHERE \n" +
        "S_SUB_WP.RECORD_STATUS = ? \n" +
        "AND S_SUB_WP.TRACK_ID = WP.TRACK_ID \n" // The same track.
        );
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append(
        "AND S_SUB_MUREUG.USER_GROUP_ID IS NOT NULL \n" // Must exists.
        );

    subQuery.append( // Complete actor.
        "AND S_SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND S_SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND S_SUB_MWPUR.WORKFLOW_ACTION <> ? \n"
        );

    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_PENDING);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_IN_PROGRESS);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_LOCK);

    return (subQuery);
  }

  // This sub query purpose to found out the staff level info of current progress's submitor.
  private AbstractQuery getSubQueryOfQueryStaffLevelInfoOfSubmitter(int level) {
    AbstractQuery subQuery = QueryUtil.createSubQuery();
    int queryIndex = 1;

    subQuery.append(
        "SELECT \n" +
        "S_SUB_STR.LEVEL_" + level + "_ID \n"
        );

    subQuery.append(
        "FROM \n" +
        "WORKFLOW_PROGRESS S_SUB_WP \n" +
        "JOIN WORKFLOW_STEP S_SUB_WS \n" +
        "ON S_SUB_WP.WORKFLOW_STEP_ID = S_SUB_WS.ID \n" +
        "AND S_SUB_WS.RECORD_STATUS = ? \n" +
        "AND S_SUB_WS.STEP_SEQ = ? \n" + // And is start step.
        "JOIN MTM_WF_PROGRESS_USER_RECORD S_SUB_MWPUR \n" +
        "ON S_SUB_MWPUR.WORKFLOW_PROGRESS_ID = S_SUB_WP.ID \n" +
        "AND S_SUB_MWPUR.RECORD_STATUS = ? \n" +
        "LEFT JOIN USER_RECORD S_SUB_URS \n" +
        "ON S_SUB_MWPUR.USER_RECORD_ID = S_SUB_URS.ID \n" +
        "AND S_SUB_URS.RECORD_STATUS = ? \n" +
        "LEFT JOIN STAFF_RECORD S_SUB_STR \n" +
        "ON S_SUB_URS.USER_LINK_ID = S_SUB_STR.ID \n" +
        "AND S_SUB_STR.RECORD_STATUS = ? \n"
        );

    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, WorkflowStep.START_STEP_SEQ_NO);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append(
        "WHERE \n" +
        "S_SUB_WP.RECORD_STATUS = ? \n" +
        "AND S_SUB_WP.TRACK_ID = WP.TRACK_ID \n" // The same track.
        );
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append(
        "AND S_SUB_STR.LEVEL_" + level + "_ID IS NOT NULL \n" // Must exists.
        );

    subQuery.append( // Complete actor.
        "AND S_SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND S_SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND S_SUB_MWPUR.WORKFLOW_ACTION <> ? \n"
        );

    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_PENDING);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_IN_PROGRESS);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_LOCK);

    return (subQuery);
  }

  // Found out the start progress and the submit user, in order to check that current user is in the submitor(s) or not.
  private AbstractQuery getSubQueryOfSubmitterOrReportToContainsCurrentUser(String actorType, Integer userRecordID) {
    AbstractQuery subQuery = QueryUtil.createSubQuery();
    int queryIndex = 1;

    subQuery.append(
        "SELECT 'X' \n"
        );

    subQuery.append(
        " FROM WORKFLOW_PROGRESS SUB_WP \n" +
        "   JOIN WORKFLOW_STEP SUB_WS \n" +
        "   ON SUB_WP.WORKFLOW_STEP_ID = SUB_WS.ID \n" +
        "   AND SUB_WS.STEP_SEQ = ? \n" + // And is start step.
        "   JOIN MTM_WF_PROGRESS_USER_RECORD SUB_MWPUR \n" +
        "   ON SUB_MWPUR.WORKFLOW_PROGRESS_ID = SUB_WP.ID \n" +
        "   AND SUB_MWPUR.RECORD_STATUS = ? \n" +
        "   LEFT JOIN USER_RECORD SUB_URS \n" +
        "   ON SUB_MWPUR.USER_RECORD_ID = SUB_URS.ID \n" +
        "   AND SUB_URS.RECORD_STATUS = ? \n" +
        "   LEFT JOIN STAFF_RECORD SUB_SR \n" +
        "   ON SUB_URS.USER_LINK_ID = SUB_SR.ID \n" +
        "   AND SUB_SR.RECORD_STATUS = ? \n" +
        "   LEFT JOIN USER_RECORD SUB_URR \n" +
        "   ON SUB_SR.REPORT_TO_STAFF_RECORD_ID = SUB_URR.USER_LINK_ID \n" +
        "   AND SUB_URR.RECORD_STATUS = ? \n"
        );

    subQuery.setParameter(queryIndex++, WorkflowStep.START_STEP_SEQ_NO);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append(
        " WHERE \n" +
        " SUB_WP.TRACK_ID = WP.TRACK_ID \n" // The same track.
        );

    subQuery.append( // Complete actor.
        "AND SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND SUB_MWPUR.WORKFLOW_ACTION <> ? \n"
        );

    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_PENDING);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_IN_PROGRESS);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_LOCK);

    if (MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER.equals(actorType)) {
      subQuery.append(
          " AND SUB_URS.ID = ? \n" // Submitter type.
          );
    } else {
      subQuery.append(
          " AND SUB_URR.ID = ? \n" // Submitter report to.
          );
    }

    subQuery.setParameter(queryIndex++, userRecordID);

    return (subQuery);
  }

  // Found out the previous progress and the actor user, in order to check that current user is in the actor(s) or not.
  private AbstractQuery getSubQueryOfPreviousActionTakerOrReportToContainsCurrentUser(String actorType, Integer userRecordID) {
    AbstractQuery subQuery = QueryUtil.createSubQuery();
    int queryIndex = 1;

    subQuery.append(
        "SELECT 'X' \n"
        );

    subQuery.append(
        " FROM MTM_WF_PROGRESS_WF_PROGRESS SUB_PP \n" +
        "   JOIN MTM_WF_PROGRESS_USER_RECORD SUB_MWPUR \n" +
        "   ON SUB_MWPUR.WORKFLOW_PROGRESS_ID = SUB_PP.PARENT_PROGRESS_ID \n" +
        "   AND SUB_MWPUR.RECORD_STATUS = ? \n" +
        "   LEFT JOIN USER_RECORD SUB_URS \n" +
        "   ON SUB_MWPUR.USER_RECORD_ID = SUB_URS.ID \n" +
        "   AND SUB_URS.RECORD_STATUS = ? \n" +
        "   LEFT JOIN STAFF_RECORD SUB_SR ON SUB_URS.USER_LINK_ID = SUB_SR.ID \n" +
        "   AND SUB_SR.RECORD_STATUS = ? \n" +
        "   LEFT JOIN USER_RECORD SUB_URR ON SUB_SR.REPORT_TO_STAFF_RECORD_ID = SUB_URR.USER_LINK_ID \n" +
        "   AND SUB_URR.RECORD_STATUS = ? \n"
        );

    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append(
        " WHERE \n" +
        " SUB_PP.CHILD_PROGRESS_ID = WP.ID \n"
        );

    subQuery.append( // Record status.
        " AND SUB_PP.RECORD_STATUS = ? \n"
        );
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append( // Complete actor.
        "AND SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND SUB_MWPUR.WORKFLOW_ACTION <> ? \n"
        );

    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_PENDING);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_IN_PROGRESS);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_LOCK);

    if (MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER.equals(actorType)) {
      subQuery.append(
          " AND SUB_URS.ID = ? \n" // Previous type.
          );
    } else {
      subQuery.append(
          " AND SUB_URR.ID = ? \n" // Previous report to.
          );
    }

    subQuery.setParameter(queryIndex++, userRecordID);

    return (subQuery);
  }

  // Found out one of preview progress and the actor user, in order to check that current user is in the actor(s) or not.
  private AbstractQuery getSubQueryOfStepActionTakerOrReportToContainsCurrentUser(String actorType, Integer userRecordID) {
    AbstractQuery subQuery = QueryUtil.createSubQuery();
    int queryIndex = 1;

    subQuery.append(
        "SELECT 'X' \n"
        );

    subQuery.append(
        " FROM WORKFLOW_PROGRESS SUB_WP \n" +
        "   JOIN MTM_WF_PROGRESS_USER_RECORD SUB_MWPUR \n" +
        "   ON SUB_MWPUR.WORKFLOW_PROGRESS_ID = SUB_WP.ID \n" +
        "   AND SUB_MWPUR.RECORD_STATUS = ? \n" +
        "   LEFT JOIN USER_RECORD SUB_URS \n" +
        "   ON SUB_MWPUR.USER_RECORD_ID = SUB_URS.ID \n" +
        "   LEFT JOIN STAFF_RECORD SUB_SR \n" +
        "   ON SUB_URS.USER_LINK_ID = SUB_SR.ID \n" +
        "   AND SUB_URS.RECORD_STATUS = ? \n" +
        "   AND SUB_SR.RECORD_STATUS = ? \n" +
        "   LEFT JOIN USER_RECORD SUB_URR \n" +
        "   ON SUB_SR.REPORT_TO_STAFF_RECORD_ID = SUB_URR.USER_LINK_ID \n" +
        "   AND SUB_URR.RECORD_STATUS = ? \n"
        );

    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append(
        " WHERE \n" +
        " SUB_WP.WORKFLOW_STEP_ID = MWSUA.ACTOR_ID \n" + // The target progress's step id is record in MWSUA.ACTOR_ID.
        " AND SUB_WP.TRACK_ID = WP.TRACK_ID \n" // Target progress(s) have the same track id with source progress.
        );

    subQuery.append( // Record status.
        " AND SUB_WP.RECORD_STATUS = ? \n"
        );
    subQuery.setParameter(queryIndex++, GlobalConstant.STATUS_ACTIVE);

    subQuery.append( // Complete actor.
        "AND SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND SUB_MWPUR.WORKFLOW_ACTION <> ? \n" +
        "AND SUB_MWPUR.WORKFLOW_ACTION <> ? \n"
        );

    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_PENDING);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_IN_PROGRESS);
    subQuery.setParameter(queryIndex++, WorkflowProgress.STATUS_LOCK);

    if (MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER.equals(actorType)) {
      subQuery.append(
          " AND SUB_URS.ID = ? \n"
          );
    } else {
      subQuery.append(
          " AND SUB_URR.ID = ? \n"
          );
    }

    subQuery.setParameter(queryIndex++, userRecordID);

    return (subQuery);
  }

  public AbstractQuery getProgressIDListSQLBySubmitterOrReportTo(String actorType, Integer userRecordID){

    AbstractQuery subQuery = new SubQuery();

    StringBuffer sqlStat = new StringBuffer();
   // List paramList = new ArrayList();
   // SqlstrAndParameters sqlStrandPara = new SqlstrAndParameters();

        sqlStat.append("SELECT  'X' \n");//DISTINCT WP.ID
        sqlStat.append("FROM WORKFLOW_RECORD R, WORKFLOW_STEP S,   MTM_WF_STEP_USER_ACTOR SUA,\n");//WORKFLOW_PROGRESS WP,
        sqlStat.append("  MTM_WF_PROGRESS_USER_RECORD PUR,WORKFLOW_PROGRESS WPX,\n");
        sqlStat.append("  USER_RECORD U LEFT JOIN STAFF_RECORD STF ON U.USER_LINK_ID=STF.ID\n");
        sqlStat.append("  LEFT JOIN USER_RECORD U2 ON STF.REPORT_TO_STAFF_RECORD_ID=U2.USER_LINK_ID\n");
        sqlStat.append("WHERE R.ID=S.WORKFLOW_RECORD_ID\n");
        sqlStat.append("  AND S.ID=WP.WORKFLOW_STEP_ID\n");
        sqlStat.append("  AND SUA.WORKFLOW_STEP_ID=WP.WORKFLOW_STEP_ID\n");
        sqlStat.append("  AND (WP.STATUS = ? OR WP.STATUS = ? OR WP.STATUS = ?) \n");
        sqlStat.append("  AND WP.COMPLETE_FLAG = ? \n");
        sqlStat.append("  AND WP.TRACK_ID=WPX.TRACK_ID\n");//
        sqlStat.append("  AND WPX.ID=PUR.WORKFLOW_PROGRESS_ID\n");//
        sqlStat.append("  AND WPX.SEQ_NO=1\n");//get the submitStep and suer
        sqlStat.append("  AND PUR.USER_RECORD_ID=U.ID\n");

        sqlStat.append("  AND SUA.ACTOR_TYPE=? \n");
        if (MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER.equals(actorType)) {
          sqlStat.append("  AND U.ID=?\n");
        } else {
          // if(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO.equals(actorType)){
          sqlStat.append("  AND U2.ID=?\n");
        }
        //EDit BY TC FOR UP
//        sqlStat.append("   AND WP.ID=PUR.WORKFLOW_PROGRESS_ID");
//        sqlStat.append("   AND WP.SEQ_NO=1 \n");
       // sqlStrandPara.setSqlStr(sqlStat.toString());
        subQuery.append(sqlStat.toString());
        int i=1;
        subQuery.setParameter(i++, WorkflowProgress.STATUS_PENDING);
        //sqlStrandPara.addParameters(WorkflowProgress.STATUS_PENDING);
        subQuery.setParameter(i++, WorkflowProgress.STATUS_IN_PROGRESS);
        //sqlStrandPara.addParameters(WorkflowProgress.STATUS_IN_PROGRESS);
        subQuery.setParameter(i++, WorkflowProgress.STATUS_LOCK);
        //sqlStrandPara.addParameters(WorkflowProgress.STATUS_LOCK);
        subQuery.setParameter(i++, GlobalConstant.FALSE);
        //sqlStrandPara.addParameters(GlobalConstant.FALSE);
        subQuery.setParameter(i++, actorType);
        //sqlStrandPara.addParameters(actorType);
        subQuery.setParameter(i++, userRecordID);
        //sqlStrandPara.addParameters(userRecordID);
        //rs = preStat.executeQuery();

    //return sqlStrandPara;
        subQuery.pack();
        return subQuery;
  }
  /**
   * Gets a list of task that are assigned to the given user record as if he/she is the previous action taker or his/her supervisor
   *
   * @param actorType Previous action taker or his/her supervisor
   * @param userRecordID The current user record id
   * @return List of desired task (WorkflowProgress) ID
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.MtmWorkflowStepUserActor
   */
  public synchronized List getProgressIDListByPreviousActionTakerOrReportTo(String actorType, Integer userRecordID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT WP.ID\n");
        sqlStat.append("FROM WORKFLOW_RECORD R, WORKFLOW_STEP S, WORKFLOW_PROGRESS WP, MTM_WF_STEP_USER_ACTOR SUA,\n");
        sqlStat.append("  MTM_WF_PROGRESS_WF_PROGRESS PP, WORKFLOW_PROGRESS WPX, MTM_WF_PROGRESS_USER_RECORD PUR,\n");
        sqlStat.append("  USER_RECORD U LEFT JOIN STAFF_RECORD STF ON U.USER_LINK_ID=STF.ID\n");
        sqlStat.append("  LEFT JOIN USER_RECORD U2 ON STF.REPORT_TO_STAFF_RECORD_ID=U2.USER_LINK_ID\n");
        sqlStat.append("WHERE R.ID=S.WORKFLOW_RECORD_ID\n");
        sqlStat.append("  AND S.ID=WP.WORKFLOW_STEP_ID\n");
        sqlStat.append("  AND SUA.WORKFLOW_STEP_ID=WP.WORKFLOW_STEP_ID\n");
        sqlStat.append("  AND PP.PARENT_PROGRESS_ID=WPX.ID\n");
        sqlStat.append("  AND PP.CHILD_PROGRESS_ID=WP.ID\n");
        sqlStat.append("  AND (WP.STATUS = ? OR WP.STATUS = ? OR WP.STATUS = ?) \n");
        sqlStat.append("  AND WP.COMPLETE_FLAG = ? \n");
        sqlStat.append("  AND WP.TRACK_ID=WPX.TRACK_ID\n");
        sqlStat.append("  AND WPX.ID=PUR.WORKFLOW_PROGRESS_ID\n");
        sqlStat.append("  AND PUR.USER_RECORD_ID=U.ID\n");
        sqlStat.append("  AND (PUR.WORKFLOW_ACTION<>? AND PUR.WORKFLOW_ACTION<>? AND PUR.WORKFLOW_ACTION<>? )\n");
        sqlStat.append("  AND SUA.ACTOR_TYPE=? \n");
        if (MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER.equals(actorType)) {
          sqlStat.append("  AND U.ID=?\n");
        } else {
          // if(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER.equals(actorType)){
          sqlStat.append("  AND U2.ID=?\n");
        }
        preStat = dbConn.prepareStatement(sqlStat.toString());
        int i = 1;
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_IN_PROGRESS);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_LOCK);
        setPrepareStatement(preStat, i++, GlobalConstant.FALSE);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_IN_PROGRESS);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_LOCK);
        setPrepareStatement(preStat, i++, actorType);
        setPrepareStatement(preStat, i++, userRecordID);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }

  public AbstractQuery getProgressIDListSQLByPreviousActionTakerOrReportTo(String actorType, Integer userRecordID){

    AbstractQuery subQuery = new SubQuery();
    //SqlstrAndParameters sqlStrandPara = new SqlstrAndParameters();
    StringBuffer sqlStat = new StringBuffer();

        sqlStat.append("SELECT  'X'\n");//DISTINCT WP.ID
        sqlStat.append("FROM WORKFLOW_RECORD R, WORKFLOW_STEP S,  MTM_WF_STEP_USER_ACTOR SUA,\n");//WORKFLOW_PROGRESS WP,
        sqlStat.append("  MTM_WF_PROGRESS_WF_PROGRESS PP,  MTM_WF_PROGRESS_USER_RECORD PUR,\n");//WORKFLOW_PROGRESS WPX,
        sqlStat.append("  USER_RECORD U LEFT JOIN STAFF_RECORD STF ON U.USER_LINK_ID=STF.ID\n");
        sqlStat.append("  LEFT JOIN USER_RECORD U2 ON STF.REPORT_TO_STAFF_RECORD_ID=U2.USER_LINK_ID\n");
        sqlStat.append("WHERE R.ID=S.WORKFLOW_RECORD_ID\n");
        sqlStat.append("  AND S.ID=WP.WORKFLOW_STEP_ID\n");
        sqlStat.append("  AND SUA.WORKFLOW_STEP_ID=WP.WORKFLOW_STEP_ID\n");
        //sqlStat.append("  AND PP.PARENT_PROGRESS_ID=WPX.ID\n");
        //sqlStat.append("  AND PP.PARENT_PROGRESS_ID=WP.ID\n");  // falcon_delete EIP-236
        sqlStat.append("  AND PP.CHILD_PROGRESS_ID=WP.ID\n");
        sqlStat.append("  AND (WP.STATUS = ? OR WP.STATUS = ? OR WP.STATUS = ?) \n");
        sqlStat.append("  AND WP.COMPLETE_FLAG = ? \n");
        //sqlStat.append("  AND WP.TRACK_ID=WPX.TRACK_ID\n");
        //sqlStat.append("  AND WPX.ID=PUR.WORKFLOW_PROGRESS_ID\n");//WHY ?
        //sqlStat.append("  AND WP.ID=PUR.WORKFLOW_PROGRESS_ID\n");//ADD BY TC  // falcon_delete EIP-236
        sqlStat.append("  AND PUR.USER_RECORD_ID=U.ID\n");
        sqlStat.append("  AND (PUR.WORKFLOW_ACTION<>? AND PUR.WORKFLOW_ACTION<>? AND PUR.WORKFLOW_ACTION<>? )\n");
        sqlStat.append("  AND SUA.ACTOR_TYPE=? \n");
        if (MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER.equals(actorType)) {
          sqlStat.append("  AND U.ID=?\n");
        } else {
          // if(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER.equals(actorType)){
          sqlStat.append("  AND U2.ID=?\n");
        }

       // sqlStrandPara.setSqlStr(sqlStat.toString());
        subQuery.append(sqlStat.toString());
        int i=1;
        subQuery.setParameter(i++, WorkflowProgress.STATUS_PENDING);
        //sqlStrandPara.addParameters(WorkflowProgress.STATUS_PENDING);
        subQuery.setParameter(i++, WorkflowProgress.STATUS_IN_PROGRESS);
        //sqlStrandPara.addParameters(WorkflowProgress.STATUS_IN_PROGRESS);
        subQuery.setParameter(i++, WorkflowProgress.STATUS_LOCK);
        //sqlStrandPara.addParameters(WorkflowProgress.STATUS_LOCK);
        subQuery.setParameter(i++, GlobalConstant.FALSE);
        //sqlStrandPara.addParameters(GlobalConstant.FALSE);
        subQuery.setParameter(i++, WorkflowProgress.STATUS_PENDING);
        //sqlStrandPara.addParameters(WorkflowProgress.STATUS_PENDING);
        subQuery.setParameter(i++, WorkflowProgress.STATUS_IN_PROGRESS);
        //sqlStrandPara.addParameters(WorkflowProgress.STATUS_IN_PROGRESS);
        subQuery.setParameter(i++, WorkflowProgress.STATUS_LOCK);
        //sqlStrandPara.addParameters(WorkflowProgress.STATUS_LOCK);
        subQuery.setParameter(i++, actorType);
        //sqlStrandPara.addParameters(actorType);
        subQuery.setParameter(i++, userRecordID);
        //sqlStrandPara.addParameters(userRecordID);

        //return sqlStrandPara;
        subQuery.pack();
        return subQuery;
  }
  /**
   * Gets a list of task that are assigned to the given user record as if he/she is a specific step's action taker or his/her supervisor
   *
   * @param actorType The specific step's action taker or his/her supervisor
   * @param userRecordID The current user record id
   * @return List of desired task (WorkflowProgress) ID
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.MtmWorkflowStepUserActor
   */
  public synchronized List getProgressIDListByStepActionTakerOrReportTo(String actorType, Integer userRecordID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT WP.ID\n");
        sqlStat.append("FROM WORKFLOW_RECORD R, WORKFLOW_STEP S, WORKFLOW_PROGRESS WP, MTM_WF_STEP_USER_ACTOR SUA,\n");
        sqlStat.append("  WORKFLOW_STEP SX, WORKFLOW_PROGRESS WPX, MTM_WF_PROGRESS_USER_RECORD PUR,\n");
        sqlStat.append("  USER_RECORD U LEFT JOIN STAFF_RECORD STF ON U.USER_LINK_ID=STF.ID \n");
        sqlStat.append("  LEFT JOIN USER_RECORD U2 ON STF.REPORT_TO_STAFF_RECORD_ID=U2.USER_LINK_ID\n");
        sqlStat.append("WHERE R.ID=S.WORKFLOW_RECORD_ID\n");
        sqlStat.append("  AND S.ID=WP.WORKFLOW_STEP_ID\n");
        sqlStat.append("  AND WP.WORKFLOW_STEP_ID=SUA.WORKFLOW_STEP_ID\n");
        sqlStat.append("  AND SUA.ACTOR_ID=SX.ID\n");
        sqlStat.append("  AND SX.ID=WPX.WORKFLOW_STEP_ID\n");
        sqlStat.append("  AND (WP.STATUS = ? OR WP.STATUS = ? OR WP.STATUS = ?) \n");
        sqlStat.append("  AND WP.COMPLETE_FLAG = ? \n");
        sqlStat.append("  AND WP.TRACK_ID=WPX.TRACK_ID\n");
        sqlStat.append("  AND WPX.ID=PUR.WORKFLOW_PROGRESS_ID\n");
        sqlStat.append("  AND PUR.USER_RECORD_ID=U.ID\n");
        sqlStat.append("  AND (PUR.WORKFLOW_ACTION<>? AND PUR.WORKFLOW_ACTION<>? AND PUR.WORKFLOW_ACTION<>? )\n");
        sqlStat.append("  AND SUA.ACTOR_TYPE=? \n");
        if (MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER.equals(actorType)) {
          sqlStat.append("  AND U.ID=?\n");
        } else {
          // if(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER.equals(actorType)){
          sqlStat.append("  AND U2.ID=?\n");
        }
        preStat = dbConn.prepareStatement(sqlStat.toString());
        int i = 1;
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_IN_PROGRESS);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_LOCK);
        setPrepareStatement(preStat, i++, GlobalConstant.FALSE);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_PENDING);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_IN_PROGRESS);
        setPrepareStatement(preStat, i++, WorkflowProgress.STATUS_LOCK);
        setPrepareStatement(preStat, i++, actorType);
        setPrepareStatement(preStat, i++, userRecordID);
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }


 public AbstractQuery getProgressIDListSQLByStepActionTakerOrReportTo(String actorType, Integer userRecordID){
   //SqlstrAndParameters sqlStrandPara = new SqlstrAndParameters();
   AbstractQuery subQuery = new SubQuery();

   StringBuffer sqlStat = new StringBuffer();

       sqlStat.append("SELECT  'X'\n");//DISTINCT WP.ID
       sqlStat.append("FROM WORKFLOW_RECORD R, WORKFLOW_STEP S,  MTM_WF_STEP_USER_ACTOR SUA,\n");//WORKFLOW_PROGRESS WP,
       sqlStat.append("  WORKFLOW_STEP SX,  MTM_WF_PROGRESS_USER_RECORD PUR,\n");//WORKFLOW_PROGRESS WPX,
       sqlStat.append("  USER_RECORD U LEFT JOIN STAFF_RECORD STF ON U.USER_LINK_ID=STF.ID \n");
       sqlStat.append("  LEFT JOIN USER_RECORD U2 ON STF.REPORT_TO_STAFF_RECORD_ID=U2.USER_LINK_ID\n");
       sqlStat.append("WHERE R.ID=S.WORKFLOW_RECORD_ID\n");
       sqlStat.append("  AND S.ID=WP.WORKFLOW_STEP_ID\n");
       sqlStat.append("  AND WP.WORKFLOW_STEP_ID=SUA.WORKFLOW_STEP_ID\n");
       sqlStat.append("  AND SUA.ACTOR_ID=SX.ID\n");
       //sqlStat.append("  AND SX.ID=WPX.WORKFLOW_STEP_ID\n");
       //sqlStat.append("  AND SX.ID=WP.WORKFLOW_STEP_ID\n");
       sqlStat.append("  AND (WP.STATUS = ? OR WP.STATUS = ? OR WP.STATUS = ?) \n");
       sqlStat.append("  AND WP.COMPLETE_FLAG = ? \n");
       //sqlStat.append("  AND WP.TRACK_ID=WPX.TRACK_ID\n");
       //sqlStat.append("  AND WPX.ID=PUR.WORKFLOW_PROGRESS_ID\n");
       //sqlStat.append("  AND WP.ID=PUR.WORKFLOW_PROGRESS_ID\n");
       sqlStat.append("  AND PUR.USER_RECORD_ID=U.ID\n");
       sqlStat.append("  AND (PUR.WORKFLOW_ACTION<>? AND PUR.WORKFLOW_ACTION<>? AND PUR.WORKFLOW_ACTION<>? )\n");
       sqlStat.append("  AND SUA.ACTOR_TYPE=? \n");
       if (MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER.equals(actorType)) {
         sqlStat.append("  AND U.ID=?\n");
       } else {
         // if(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER.equals(actorType)){
         sqlStat.append("  AND U2.ID=?\n");
       }
       subQuery.append(sqlStat.toString());

       int i = 1;
       subQuery.setParameter(i++, WorkflowProgress.STATUS_PENDING);
       //sqlStrandPara.addParameters(WorkflowProgress.STATUS_PENDING);
       subQuery.setParameter(i++, WorkflowProgress.STATUS_IN_PROGRESS);
       //sqlStrandPara.addParameters(WorkflowProgress.STATUS_IN_PROGRESS);
       subQuery.setParameter(i++, WorkflowProgress.STATUS_LOCK);
       //sqlStrandPara.addParameters(WorkflowProgress.STATUS_LOCK);
       subQuery.setParameter(i++, GlobalConstant.FALSE);
       //sqlStrandPara.addParameters(GlobalConstant.FALSE);
       subQuery.setParameter(i++, WorkflowProgress.STATUS_PENDING);
       //sqlStrandPara.addParameters(WorkflowProgress.STATUS_PENDING);
       subQuery.setParameter(i++, WorkflowProgress.STATUS_IN_PROGRESS);
       //sqlStrandPara.addParameters(WorkflowProgress.STATUS_IN_PROGRESS);
       subQuery.setParameter(i++, WorkflowProgress.STATUS_LOCK);
       //sqlStrandPara.addParameters(WorkflowProgress.STATUS_LOCK);
       subQuery.setParameter(i++, actorType);
       //sqlStrandPara.addParameters(actorType);
       subQuery.setParameter(i++, userRecordID);
       //sqlStrandPara.addParameters(userRecordID);

       //sqlStrandPara.setSqlStr(sqlStat.toString());

      // return sqlStrandPara;
       subQuery.pack();
       return subQuery;
 }
  /**
   * Gets a list of task of attachment name
   *
   * @param attachmentName The attachment name
   * @return List of desired task (WorkflowProgress) ID
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.MtmWorkflowStepUserActor
   */
  public synchronized List getProgressIDListByAttachmentName(String attachmentName) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    List resultList = new ArrayList();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT DISTINCT A.WORKFLOW_PROGRESS_ID \n");
        sqlStat.append("FROM MTM_WF_PROGRESS_USER_RECORD A, WORKFLOW_PROGRESS_ATTACHMENT B \n");
        sqlStat.append("WHERE A.ID = B.MTM_WF_PROGRESS_USER_RECORD_ID \n");
        sqlStat.append("  AND   A.RECORD_STATUS = B.RECORD_STATUS \n");
        sqlStat.append("  AND   A.RECORD_STATUS = ? \n");
        sqlStat.append("  AND   ").append(this.getSearchColumn("ATTACHMENT_NAME", "B")).append(" LIKE ? \n");

        String attachmentNameStr = this.getFormattedKeyword(attachmentName, "LIKE");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        setPrepareStatement(preStat, 2, this.getFormattedKeyword(attachmentNameStr, "LIKE"));
        rs = preStat.executeQuery();
        while (rs.next()) {
          resultList.add(getResultSetInteger(rs, "WORKFLOW_PROGRESS_ID"));
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
    return resultList;
  }


  //ADD BY TC FOR TEST
  public AbstractQuery getProgressIDsSQLByAttachmentName(String attachmentName){
    //SqlstrAndParameters strAndPara = new SqlstrAndParameters();
    AbstractQuery subQuery = new SubQuery();
    StringBuffer sqlStat = new StringBuffer();

    sqlStat.append("SELECT DISTINCT A.WORKFLOW_PROGRESS_ID \n");
    sqlStat.append("FROM MTM_WF_PROGRESS_USER_RECORD A, WORKFLOW_PROGRESS_ATTACHMENT B \n");
    sqlStat.append("WHERE A.ID = B.MTM_WF_PROGRESS_USER_RECORD_ID \n");
    sqlStat.append("  AND   A.RECORD_STATUS = B.RECORD_STATUS \n");
    sqlStat.append("  AND   A.RECORD_STATUS = ? \n");
    sqlStat.append("  AND   ").append(this.getSearchColumn("ATTACHMENT_NAME", "B")).append(" LIKE ? \n");

    //strAndPara.addParameters(GlobalConstant.RECORD_STATUS_ACTIVE);
    //strAndPara.addParameters(this.getFormattedKeyword(attachmentName, "LIKE"));
    //strAndPara.setSqlStr(sqlStat.toString());
    //return strAndPara;
    subQuery.append(sqlStat.toString());
    subQuery.setParameter(1, GlobalConstant.RECORD_STATUS_ACTIVE);
    subQuery.setParameter(2, this.getFormattedKeyword(attachmentName, "LIKE"));
    return subQuery;
  }
  /**
   * Gets the first progress object by workflow track.
   *
   * @param trackID The workflow track ID
   * @return The system object(WorkflowProgress)
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public synchronized AbstractBaseObject getFirstProgressByTrackID(Integer trackID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE, ");
        sqlStat.append("       WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ALLOW_ASSIGN_DUE_DATE, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ALLOW_STOP, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR ");
        sqlStat.append("FROM   WORKFLOW_PROGRESS A, WORKFLOW_STEP WS, WORKFLOW_RECORD WR, SETUP_OPTION_WORKFLOW_CATEGORY SOWC ");
        sqlStat.append("WHERE  A.TRACK_ID = ? AND A.SEQ_NO = ? AND A.RECORD_STATUS = ? AND ");
        sqlStat.append("       A.WORKFLOW_STEP_ID = WS.ID AND ");
        sqlStat.append("       WS.WORKFLOW_RECORD_ID = WR.ID AND ");
        sqlStat.append("       WR.WORKFLOW_CATEGORY_ID = SOWC.ID ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, trackID);
        this.setPrepareStatement(preStat, 2, new Integer(1));
        this.setPrepareStatement(preStat, 3, GlobalConstant.RECORD_STATUS_ACTIVE);
        rs = preStat.executeQuery();
        if (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          tmpWorkflowProgress.setCancelFlag(getResultSetString(rs, "CANCEL_FLAG"));
          tmpWorkflowProgress.setCompleteFlag(getResultSetString(rs, "COMPLETE_FLAG"));
          tmpWorkflowProgress.setSeqNo(getResultSetInteger(rs, "SEQ_NO"));
          tmpWorkflowProgress.setStatus(getResultSetString(rs, "STATUS"));
          tmpWorkflowProgress.setPostProgress(getResultSetString(rs, "POST_PROGRESS"));
          tmpWorkflowProgress.setDueDate(getResultSetTimestamp(rs, "DUE_DATE"));
          tmpWorkflowProgress.setNextStepDueDates(getResultSetString(rs, "NEXT_STEP_DUE_DATES"));
          tmpWorkflowProgress.setProgressPriority(getResultSetString(rs, "PROGRESS_PRIORITY"));
          tmpWorkflowProgress.setUserDef1(getResultSetString(rs, "USER_DEF_1"));
          tmpWorkflowProgress.setUserDef2(getResultSetString(rs, "USER_DEF_2"));
          tmpWorkflowProgress.setUserDef3(getResultSetString(rs, "USER_DEF_3"));
          tmpWorkflowProgress.setUserDef4(getResultSetString(rs, "USER_DEF_4"));
          tmpWorkflowProgress.setUserDef5(getResultSetString(rs, "USER_DEF_5"));
          tmpWorkflowProgress.setRecordStatus(getResultSetString(rs, "RECORD_STATUS"));
          tmpWorkflowProgress.setUpdateCount(getResultSetInteger(rs, "UPDATE_COUNT"));
          tmpWorkflowProgress.setCreatorID(getResultSetInteger(rs, "CREATOR_ID"));
          tmpWorkflowProgress.setCreateDate(getResultSetTimestamp(rs, "CREATE_DATE"));
          tmpWorkflowProgress.setUpdaterID(getResultSetInteger(rs, "UPDATER_ID"));
          tmpWorkflowProgress.setUpdateDate(getResultSetTimestamp(rs, "UPDATE_DATE"));
          tmpWorkflowProgress.setCreatorName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getCreatorID()));
          tmpWorkflowProgress.setUpdaterName(UserInfoFactory.getUserFullName(tmpWorkflowProgress.getUpdaterID()));
          tmpWorkflowProgress.setWorkflowCode(getResultSetString(rs, "WORKFLOW_CODE"));
          tmpWorkflowProgress.setWorkflowVersion(getResultSetString(rs, "WORKFLOW_VERSION"));
          tmpWorkflowProgress.setWorkflowDescription(getResultSetString(rs, "WORKFLOW_DESCRIPTION"));
          tmpWorkflowProgress.setWorkflowCategory(getResultSetString(rs, "WORKFLOW_CATEGORY_NAME"));
          tmpWorkflowProgress.setWorkflowCategoryID(getResultSetInteger(rs, "WORKFLOW_CATEGORY_ID"));
          tmpWorkflowProgress.setWorkflowRecordID(getResultSetInteger(rs, "WORKFLOW_RECORD_ID"));
          tmpWorkflowProgress.setStepSeq(getResultSetInteger(rs, "STEP_SEQ"));
          tmpWorkflowProgress.setStepName(getResultSetString(rs, "STEP_NAME"));
          tmpWorkflowProgress.setAllowAssignDueDate(getResultSetString(rs, "ALLOW_ASSIGN_DUE_DATE"));
          tmpWorkflowProgress.setActionType(getResultSetString(rs, "ACTION_TYPE"));
          tmpWorkflowProgress.setStepDescription(getResultSetString(rs, "STEP_DESCRIPTION"));
          tmpWorkflowProgress.setPriority(getResultSetString(rs, "PRIORITY"));
          tmpWorkflowProgress.setAllowStop(getResultSetString(rs, "ALLOW_STOP"));
          tmpWorkflowProgress.setOnNoResponseAfter(getResultSetTimestamp(rs, "ON_NO_RESPONSE_AFTER"));
          tmpWorkflowProgress.setOnNoResponseFor(getResultSetInteger(rs, "ON_NO_RESPONSE_FOR"));
          tmpWorkflowProgress.setStartDate(getResultSetTimestamp(rs, "START_DATE"));
          tmpWorkflowProgress.setEndDate(getResultSetTimestamp(rs, "END_DATE"));

          WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionContainer, dbConn);
          tmpWorkflowProgress.setWorkflowStepSource((WorkflowStep) stepDAO.getObjectByID(tmpWorkflowProgress.getWorkflowStepID()));

          return (tmpWorkflowProgress);
        } else {
          return null;
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Set the Progress Count for every delegation user of the List
   * @author Samlin
   * @param delegationList
   * @throws Exception
   * @throws SQLException
   * @throws Exception
   * @throws SQLException
   */
  public List setPendingUserListCount(List delegationList) {

    ListWorkflowProgressForm searchForm = getMockWorkFlowProgressForm();

    for (Iterator iter = delegationList.iterator(); iter.hasNext();) {
      UserDelegation element = (UserDelegation) iter.next();
      try {
        if (element != null) {
          UserRecord userRecord = new UserRecord();
          userRecord.setID(element.getSourceUserID());
          searchForm.setDelegateUserRecordID(element.getSourceUserID().toString());

          //int count = this.getGeneralUserCount(this.getPendUserSqlStr(searchForm, false, userRecord));
          //int dynamicCount = this.getDynamicUserCount(this.getDynamicUserSqlStr(searchForm, false,userRecord));
          //count = count + dynamicCount;
          int count = getPendingUserListCount(searchForm,userRecord);
          element.setSourceUserName(element.getSourceUserName() + " (" + String.valueOf(count) + ")");
        }
      } catch (Exception e) {
        log.error(e, e);
      }
    }
    return delegationList;

  }

  private int getPendingUserListCount(AbstractSearchForm searchForm,UserRecord userRecord) throws SQLException, Exception {
    AbstractQuery query = QueryUtil.createQuery();
    AbstractQuery pendUserSql = getPendUserSqlStr(searchForm, false, userRecord);

    int totalNumOfRecord = 0;

    query.subQuery(pendUserSql);

    AbstractQuery dynamicUserSql = getDynamicUserSqlStr(searchForm, false,userRecord);

    StringBuffer sqlDynamicUser1=getUserFilterBy(searchForm, false,userRecord);

    query.append(" UNION ");
    query.subQuery(dynamicUserSql);
    query.append(" UNION ");
    query.append(sqlDynamicUser1.toString());
    query.pack();


    StringBuffer tempStr = this.getFormattedSQL(query.toString());


    StringBuffer sqlStatCnt = new StringBuffer(" SELECT COUNT(*) FROM ( "+tempStr.toString()+" ) UnionCount ");

    PreparedStatement preStatCnt = dbConn.prepareStatement(sqlStatCnt.toString());

            int cntIndex =this.setPreparedStatement(preStatCnt,1,query.getAllParameters());

            setDynamicPreStatementFilterBy(searchForm, preStatCnt, userRecord.getID(), false, cntIndex);

            ResultSet rsCnt = preStatCnt.executeQuery();
            if (rsCnt.next()) {
              totalNumOfRecord = rsCnt.getInt(1);
            }
            try { rsCnt.close(); } catch (Exception ignore) {} finally { rsCnt = null; }
            try { preStatCnt.close(); } catch (Exception ignore) {} finally { preStatCnt = null; }

            return totalNumOfRecord;
  }

  private ListWorkflowProgressForm getMockWorkFlowProgressForm() {
    ListWorkflowProgressForm searchForm = new ListWorkflowProgressForm();
    searchForm.setCurStartRowNo("1");
    searchForm.setPageOffset("10");
    searchForm.setCurStartRowNo("1");
    searchForm.setCurStartRowNo("1");
    searchForm.setCurStartRowNo("1");
    return searchForm;
  }

  /**
   * get the deny progress ID list
   * @return List
   * @throws ApplicationException
   */
  private List getDenyProgressIDList() throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    PermissionManager pm = sessionContainer.getPermissionManager();
    Integer userRecordID = pm.getUserRecordID();
    List userRolesList = pm.getUserRoles();
    List userGroupsList = pm.getUserGroups();

    String userGroupIDs = "-1";
    String userRoleIDs = "-1";

    for (int i = 0; userGroupsList != null && i < userGroupsList.size(); i++) {
      userGroupIDs += ", ";

      UserGroup group = (UserGroup) userGroupsList.get(i);
      userGroupIDs += group.getID();
    }

    for (int i = 0; userRolesList != null && i < userRolesList.size(); i++) {
      userRoleIDs += ", ";
      UserRole role = (UserRole) userRolesList.get(i);
      userRoleIDs += role.getID();
    }

    List progressIDList = new ArrayList();
    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT B.ID ");
        sqlStat.append("FROM MTM_WF_STEP_USER_ACTOR A, WORKFLOW_PROGRESS B ");
        sqlStat.append("WHERE  A.RECORD_STATUS = ? ");
        sqlStat.append("       AND A.RECORD_STATUS = B.RECORD_STATUS ");
        sqlStat.append("       AND A.WORKFLOW_STEP_ID = B.WORKFLOW_STEP_ID ");
        sqlStat.append("       AND ( ( A.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_USER + "' AND A.ACTOR_ID = ? )");
        sqlStat.append("            OR ( A.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE + "' AND A.ACTOR_ID IN (" + userRoleIDs + ")) ");
        sqlStat.append("            OR ( A.ACTOR_TYPE = '" + MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP + "' AND A.ACTOR_ID IN (" + userGroupIDs + ")) ");
        sqlStat.append("            ) ");

        if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_MYSQL) {
          sqlStat.append("AND  BINARY A.PERMISSION LIKE  ? ");
        }else if(DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_MSSQL){
          sqlStat.append("AND A.PERMISSION collate Chinese_PRC_CS_AS_WS LIKE ? ");
        }
        else {
          sqlStat.append("AND  A.PERMISSION LIKE  ? ");
        }
        log.debug("----------------------------------------" + sqlStat.toString());
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
        this.setPrepareStatement(preStat, 2, userRecordID);
        if(DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_ORACLE){
        this.setPrepareStatement(preStat,3,WorkflowProgressDAObject.WORKFLOW_PERMISSION_TYPE_DENY_EXECUTE);
        }else{
        this.setPrepareStatement(preStat, 3, this.getFormattedKeyword(WorkflowProgressDAObject.WORKFLOW_PERMISSION_TYPE_DENY_EXECUTE, "LIKE"));
        }
        rs = preStat.executeQuery();
        while (rs.next()) {
          progressIDList.add(getResultSetInteger(rs, "ID"));
        }
        return progressIDList;
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * Get progressID
   * @param progressID
   * @param userRecordID
   * @param trackID
   * @return
   * @throws ApplicationException
   */
  public synchronized Integer getWorkflowProgressIDByStepIDTrackID(Integer stepID, Integer trackID) throws ApplicationException {
    PreparedStatement preStat = null;
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();

    synchronized (dbConn) {
      try {
        sqlStat.append("SELECT ID  ");
        sqlStat.append("FROM WORKFLOW_PROGRESS ");
        sqlStat.append("WHERE WORKFLOW_STEP_ID = ? ");
        sqlStat.append("AND TRACK_ID = ? ");
        preStat = dbConn.prepareStatement(sqlStat.toString());
        setPrepareStatement(preStat, 1, stepID);
        setPrepareStatement(preStat, 2, trackID);
        rs = preStat.executeQuery();
        if (rs.next()) {
          return getResultSetInteger(rs, "ID");
        } else {
          return null;
        }
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle);
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
    }
  }

  /**
   * cancel the workflow track by the given ProgressID (Mark the complete_flag of the whole track to GlobalConstant.FALSE)
   *
   * @param ProgressID The workflow ProgressID
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  //public synchronized void cancelWorkflowByTrackID(Integer trackID) throws ApplicationException {//simon_del
  public synchronized void cancelWorkflowByProgressID(Integer progressID) throws ApplicationException {//simon_add
    PreparedStatement preStat = null;
    StringBuffer sqlStat = new StringBuffer();

    synchronized(dbConn) {
      try {
        int updateCnt = 0;
        Timestamp currTime = Utility.getCurrentTimestamp();
        sqlStat.append("UPDATE WORKFLOW_PROGRESS \n");
        sqlStat.append("SET  CANCEL_FLAG=?, STATUS=?, UPDATER_ID=?, UPDATE_DATE=? \n");//kneey_update
        //sqlStat.append("WHERE TRACK_ID=?");//simon_del
        sqlStat.append("WHERE ID=?");//simon_add
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        setPrepareStatement(preStat, 1, GlobalConstant.TRUE);
        setPrepareStatement(preStat, 2, WorkflowProgress.STATUS_CANCEL);
        setPrepareStatement(preStat, 3, sessionContainer.getUserRecordID());//kneey_add
        setPrepareStatement(preStat, 4, currTime);//kneey_add
        //setPrepareStatement(preStat, 3, trackID);//simon_del
        setPrepareStatement(preStat, 5, progressID);//simon_add
        updateCnt = preStat.executeUpdate();
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_UPDATE_ERROR, e);
      } finally {
        try { preStat.close(); } catch (Exception ignore) {} finally { preStat = null; }
      }
    }
  }
  //king---add---start
  protected synchronized List getDynamicList() throws ApplicationException {
      PreparedStatement preStat = null;
      ResultSet rs = null;
      StringBuffer sqlStat = new StringBuffer();
      List result = new ArrayList();

      synchronized (dbConn) {
        try {
          sqlStat.append("select distinct wp.id,wp.workflow_step_id,wp.track_id ");
          sqlStat.append("       from workflow_progress wp, ");
          sqlStat.append("MTM_WF_DYNAMIC_USER_ACTOR dua,workflow_step ws ");
          sqlStat.append("where dua.workflow_progress_id=wp.id ");
          sqlStat.append("and dua.record_status=wp.record_status ");
          sqlStat.append("and dua.record_status=ws.record_status ");
          sqlStat.append("and ws.id=wp.workflow_step_id  ");
          sqlStat.append("and ws.filter_by is not null ");
          sqlStat.append("and dua.record_status=? ");
          sqlStat.append("and wp.status=? ");
          preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
          this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
          this.setPrepareStatement(preStat, 2, WorkflowProgress.STATUS_PENDING);
          rs = preStat.executeQuery();
          while (rs.next()) {
            WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
            tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
            tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
            tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
            result.add(tmpWorkflowProgress);
          }
          return (result);
        } catch (ApplicationException appEx) {
          throw appEx;
        } catch (SQLException sqle) {
          log.error(sqle, sqle);
          throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
        } catch (Exception e) {
          log.error(e, e);
          throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
        } finally {
          try {
            rs.close();
          } catch (Exception ignore) {
          } finally {
            rs = null;
          }
          try {
            preStat.close();
          } catch (Exception ignore) {
          } finally {
            preStat = null;
          }
        }
      }
    }

  private synchronized List getFilterDynamicList(AbstractSearchForm searchForm, boolean bFullList,UserRecord userRecord) throws ApplicationException {

      AbstractQuery subQuery = new SubQuery();
      AbstractQuery strAndParaprogressIDs = getCompletedProgressIDListSQLByUserRecordID(this.sessionContainer.getUserRecordID());


      UserDelegationDAObject delegateDAO = new UserDelegationDAObject(this.sessionContainer,this.dbConn);
      List delegateUserList = delegateDAO.getListDelegatedToUser();
      List userIDList = new ArrayList();
      userIDList.add(userRecord.getID());
      try {
        if(searchForm instanceof ListWorkflowProgressForm&&((ListWorkflowProgressForm)searchForm).isIncludeDelegateReocrd()){
          userIDList.addAll(Utility.getPropertyList(delegateUserList, "sourceUserID"));
        }
      } catch (Exception e) {

      }
      StringBuffer userIDsStr = new StringBuffer();
      for(int i=0;i<userIDList.size();i++){
        if(i==0){
          userIDsStr.append(userIDList.get(i).toString());
        }else{
          userIDsStr.append(" , ").append(userIDList.get(i).toString());
        }
      }



      subQuery.append("SELECT  WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.SEQ_NO, WP.STATUS, WP.POST_PROGRESS, WP.DUE_DATE, WP.UPDATE_DATE AS UPDATE_DATE, WP.NEXT_STEP_DUE_DATES, WP.PROGRESS_PRIORITY,  WP.RECORD_STATUS,  WP.CREATOR_ID, WP.CREATE_DATE, WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE,   WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE,  WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR, WSTAGE.STAGE_NAME \n");
      subQuery.append(" FROM WORKFLOW_RECORD WR, WORKFLOW_STEP WS LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON SS.WORKFLOW_STEP_ID = WS.ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON WSTAGE.ID = SS.WORKFLOW_STAGE_ID, WORKFLOW_PROGRESS WP ");
      subQuery.append("      LEFT JOIN MTM_WF_PROGRESS_USER_RECORD MWPUR ON WP.ID = MWPUR.WORKFLOW_PROGRESS_ID   \n");
      subQuery.append("      , MTM_WF_DYNAMIC_USER_ACTOR DUA, SETUP_OPTION_WORKFLOW_CATEGORY SOWC, \n");
      subQuery.append("      USER_RECORD U \n");
      subQuery.append("      LEFT JOIN MTM_USER_RECORD_USER_GROUP UG ON U.ID = UG.USER_RECORD_ID AND UG.RECORD_STATUS = U.RECORD_STATUS \n");
      subQuery.append("      LEFT JOIN MTM_USER_RECORD_USER_ROLE UR ON U.ID = UR.USER_RECORD_ID AND UR.RECORD_STATUS = U.RECORD_STATUS \n");
      subQuery.append("      LEFT JOIN MTM_USER_GROUP_USER_ROLE GR ON UG.USER_GROUP_ID = GR.USER_GROUP_ID AND GR.RECORD_STATUS = U.RECORD_STATUS \n");
      subQuery.append(" WHERE WR.ID = WS.WORKFLOW_RECORD_ID \n");
      subQuery.append(" AND WS.ID = WP.WORKFLOW_STEP_ID \n");
      subQuery.append(" AND WR.WORKFLOW_CATEGORY_ID = SOWC.ID \n");
      subQuery.append(" AND WR.RECORD_STATUS = DUA.RECORD_STATUS \n");
      subQuery.append(" AND WS.RECORD_STATUS = DUA.RECORD_STATUS \n");
      subQuery.append(" AND WS.FILTER_BY IS NOT NULL \n");//select filter dynamicList
      subQuery.append(" AND SOWC.RECORD_STATUS = DUA.RECORD_STATUS \n");
      subQuery.append(" AND U.RECORD_STATUS = DUA.RECORD_STATUS \n");
      subQuery.append(" AND DUA.WORKFLOW_PROGRESS_ID = WP.ID \n");
      subQuery.append(" AND DUA.RECORD_STATUS = ? \n"); // 'A'
      subQuery.append(" AND ( (DUA.ACTOR_TYPE = ? AND DUA.ACTOR_ID = U.ID) OR \n"); // 'U'
      subQuery.append("       (DUA.ACTOR_TYPE = ? AND DUA.ACTOR_ID = UG.USER_GROUP_ID) OR \n"); // 'G'
      subQuery.append("       (DUA.ACTOR_TYPE = ? AND (DUA.ACTOR_ID = GR.USER_ROLE_ID OR DUA.ACTOR_ID = UR.USER_ROLE_ID)) \n"); // 'R'
      subQuery.append("     ) \n");

      subQuery.append(" AND NOT EXISTS (SELECT 'X' \n");
      subQuery.append(" FROM  MTM_WF_PROGRESS_USER_RECORD PUR \n");
      subQuery.append(" WHERE PUR.WORKFLOW_PROGRESS_ID = WP.ID \n");
      subQuery.append(" AND PUR.USER_RECORD_ID = ? \n");
      subQuery.append(" AND PUR.WORKFLOW_ACTION = ?) AND \n");

      if (bFullList) {
        subQuery.append("        WP.STATUS <> ? AND \n");
        subQuery.append("        MWPUR.WORKFLOW_ACTION <> ? AND \n");
      } else {
        subQuery.append("        (WP.STATUS = ? OR WP.STATUS = ? OR WP.STATUS = ?) AND \n");
        subQuery.append("        WP.COMPLETE_FLAG = ? AND \n");

        subQuery.append(" WP.ID NOT IN (").subQuery(strAndParaprogressIDs).append(" ) AND \n");
      }
        subQuery.append(this.getInSQL("U.ID", userIDsStr.toString()));


      // ##################################################################
      // Form the WHERE clause for filtering.
      if (searchForm.isSearchable()) {
        String searchField = getSearchColumn(searchForm.getBasicSearchField(), "WP");
        subQuery.append("AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? ");
      }

      if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_MYSQL) {
        subQuery.append("AND  BINARY DUA.PERMISSION LIKE  ? ");
      } else {
        subQuery.append("AND  DUA.PERMISSION LIKE  ? ");
      }

      if (searchForm instanceof ListWorkflowProgressForm) {
        subQuery.subQuery(getDynamicUserSearchSqlStr(searchForm));
      }


      //---set Params--
      int i=1;
      subQuery.setParameter(i++, GlobalConstant.RECORD_STATUS_ACTIVE);
      subQuery.setParameter(i++, GlobalConstant.SUBJECT_TYPE_USER);
      subQuery.setParameter(i++, GlobalConstant.SUBJECT_TYPE_GROUP);
      subQuery.setParameter(i++, GlobalConstant.SUBJECT_TYPE_ROLE);
      subQuery.setParameter(i++, userRecord.getID());
      subQuery.setParameter(i++, WorkflowProgress.STATUS_GENERAL_ACCOMPLISHMENT);
      if (bFullList) {
        subQuery.setParameter(i++, WorkflowProgress.STATUS_SUBMIT);
        subQuery.setParameter(i++, WorkflowProgress.STATUS_SUBMIT);
      }else{
        subQuery.setParameter(i++, WorkflowProgress.STATUS_PENDING);
        subQuery.setParameter(i++, WorkflowProgress.STATUS_IN_PROGRESS);
        subQuery.setParameter(i++, WorkflowProgress.STATUS_LOCK);
        subQuery.setParameter(i++, GlobalConstant.FALSE);
      }
        //strAndPara.addParameters(userRecord.getID());
        //subQuery.setParameter(i++, userRecord.getID());

     if (searchForm.isSearchable()) {
       String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
       subQuery.setParameter(i++, searchKeyword);
     }
      String permissionKeyword = this.getFormattedKeyword(WORKFLOW_PERMISSION_TYPE_EXECUTE, "LIKE");
      //strAndPara.addParameters(permissionKeyword);
      subQuery.setParameter(i++, permissionKeyword);
      subQuery.pack();


      PreparedStatement preStat = null;
      ResultSet rs = null;
      StringBuffer sqlStat = new StringBuffer();
      List result = new ArrayList();

      try{
        sqlStat = this.getFormattedSQL(subQuery.toString());
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        this.setPreparedStatement(preStat,1,subQuery.getAllParameters());
        rs = preStat.executeQuery();
        while (rs.next()) {
          WorkflowProgress tmpWorkflowProgress = new WorkflowProgress();
          tmpWorkflowProgress.setID(getResultSetInteger(rs, "ID"));
          tmpWorkflowProgress.setWorkflowStepID(getResultSetInteger(rs, "WORKFLOW_STEP_ID"));
          tmpWorkflowProgress.setTrackID(getResultSetInteger(rs, "TRACK_ID"));
          result.add(tmpWorkflowProgress);
        }
        return (result);
      }catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
        }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
        }
      }
  }
  private StringBuffer getUserFilterBy(AbstractSearchForm searchForm, boolean bFullList,UserRecord userRecord) throws ApplicationException {
      String progressIDs = "-1";
      String flag="-1";
      //get the completed progress ID string for the dynamic assign user by the user record ID
      List list=this.getFilterDynamicList(searchForm,bFullList,userRecord);
      Iterator it=list.iterator();
      WorkflowStepDAObject wsDAO=new WorkflowStepDAObject(this.sessionContainer,this.dbConn);
      ArrayList userList=new ArrayList();
      userList.add(getEffectiveUserRecordID(searchForm));
      while(it.hasNext()){
        WorkflowProgress wprogress=(WorkflowProgress)it.next();
        WorkflowStep wstep=(WorkflowStep)wsDAO.getByID(wprogress.getWorkflowStepID());
        List tempList=wsDAO.getfilteredListProgressIDsFromWFStep(userList, wstep, wprogress);
        if(!Utility.isEmpty(tempList)){
          for(int i=0;i<tempList.size();i++){
            String tempStr=((Integer)tempList.get(i)).toString();
            if(!tempStr.equals(flag)){
              progressIDs+="," +tempStr ;
              flag=tempStr;
            }
          }
        }
      }
      StringBuffer sqlStat3 = new StringBuffer();
      //sqlStat3.append(" SELECT  DISTINCT WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.SEQ_NO, WP.STATUS, WP.POST_PROGRESS, WP.DUE_DATE, WP.NEXT_STEP_DUE_DATES, WP.PROGRESS_PRIORITY, WP.USER_DEF_1, WP.USER_DEF_2, WP.USER_DEF_3, WP.USER_DEF_4, WP.USER_DEF_5, WP.RECORD_STATUS, WP.UPDATE_COUNT, WP.CREATOR_ID, WP.CREATE_DATE, WP.UPDATER_ID, WP.UPDATE_DATE AS UPDATE_DATE, WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE, WR.DESCRIPTION AS WORKFLOW_DESCRIPTION, SOWC.WORKFLOW_CATEGORY_NAME, WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE, WS.DESCRIPTION AS STEP_DESCRIPTION, WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR, WSTAGE.STAGE_NAME  \n");
      sqlStat3.append("SELECT  WP.ID, WP.WORKFLOW_STEP_ID, WP.TRACK_ID, WP.CANCEL_FLAG, WP.COMPLETE_FLAG, WP.SEQ_NO, WP.STATUS, WP.POST_PROGRESS, WP.DUE_DATE, WP.UPDATE_DATE AS UPDATE_DATE,  WP.NEXT_STEP_DUE_DATES, WP.PROGRESS_PRIORITY,  WP.RECORD_STATUS,  WP.CREATOR_ID, WP.CREATE_DATE, WR.WORKFLOW_CODE, WR.WORKFLOW_VERSION, WR.START_DATE, WR.END_DATE,   WR.WORKFLOW_CATEGORY_ID, WR.ID AS WORKFLOW_RECORD_ID, WS.STEP_SEQ, WS.STEP_NAME, WS.ACTION_TYPE,  WS.PRIORITY, WS.ON_NO_RESPONSE_AFTER, WS.ON_NO_RESPONSE_FOR, WSTAGE.STAGE_NAME \n");
      sqlStat3.append(" FROM WORKFLOW_RECORD WR, WORKFLOW_STEP WS LEFT JOIN MTM_WF_STAGE_WF_STEP SS ON SS.WORKFLOW_STEP_ID = WS.ID LEFT JOIN WORKFLOW_STAGE WSTAGE ON WSTAGE.ID = SS.WORKFLOW_STAGE_ID, WORKFLOW_PROGRESS WP ");
      sqlStat3.append("      LEFT JOIN MTM_WF_PROGRESS_USER_RECORD MWPUR ON WP.ID = MWPUR.WORKFLOW_PROGRESS_ID   \n");
      sqlStat3.append("      , MTM_WF_DYNAMIC_USER_ACTOR DUA, SETUP_OPTION_WORKFLOW_CATEGORY SOWC \n");
      sqlStat3.append(" WHERE WR.ID = WS.WORKFLOW_RECORD_ID \n");
      sqlStat3.append(" AND WS.ID = WP.WORKFLOW_STEP_ID \n");
      sqlStat3.append(" AND WR.WORKFLOW_CATEGORY_ID = SOWC.ID \n");
      sqlStat3.append(" AND WR.RECORD_STATUS = DUA.RECORD_STATUS \n");
      sqlStat3.append(" AND WS.RECORD_STATUS = DUA.RECORD_STATUS \n");
      sqlStat3.append(" AND WS.filter_by is not null \n");
      sqlStat3.append(" AND SOWC.RECORD_STATUS = DUA.RECORD_STATUS \n");
      sqlStat3.append(" AND DUA.WORKFLOW_PROGRESS_ID = WP.ID \n");
      sqlStat3.append(" AND DUA.RECORD_STATUS = ? \n"); // 'A'
      sqlStat3.append(" AND (MWPUR.WORKFLOW_PROGRESS_ID IS NULL OR MWPUR.WORKFLOW_PROGRESS_ID = WP.ID) AND \n");
      if (bFullList) {
        sqlStat3.append("        WP.STATUS <> ? AND \n");
        sqlStat3.append("        MWPUR.WORKFLOW_ACTION <> ? AND \n");
      } else {
        sqlStat3.append("        (WP.STATUS = ? OR WP.STATUS = ? OR WP.STATUS = ?) AND \n");
        sqlStat3.append("        WP.COMPLETE_FLAG = ? AND \n");
        sqlStat3.append("        (WS.WORKFLOW_RULE = '*' OR MWPUR.WORKFLOW_ACTION IS NULL OR MWPUR.WORKFLOW_ACTION = ? OR MWPUR.WORKFLOW_ACTION = ? OR MWPUR.WORKFLOW_ACTION = ? ) AND \n"); // 'P', 'I', 'L'
        sqlStat3.append("        WP.ID IN (" + progressIDs + ")  \n");
      }


      // ##################################################################
      // Form the WHERE clause for filtering.
      if (searchForm.isSearchable()) {
        String searchField = getSearchColumn(searchForm.getBasicSearchField(), "WP");
        sqlStat3.append("AND  " + searchField + " " + searchForm.getBasicSearchType() + " ? ");
      }
      if (DataSourceFactory.getDatabaseType() == DataSourceFactory.DB_MYSQL) {
        sqlStat3.append("AND  BINARY DUA.PERMISSION LIKE  ? ");
      } else {
        sqlStat3.append("AND  DUA.PERMISSION LIKE  ? ");
      }

      if (searchForm instanceof ListWorkflowProgressForm) {
        sqlStat3.append(getDynamicUserSearchSql(searchForm));
        }

      return sqlStat3;
    }

  private int getUserCountFilterBy(AbstractSearchForm searchForm, boolean bFullList, UserRecord userRecord) throws Exception {
      StringBuffer sqlDynamicUser = getUserFilterBy(searchForm, bFullList,userRecord);
      if (searchForm instanceof ListWorkflowProgressForm) {
        sqlDynamicUser.append(getDynamicUserSearchSql(searchForm));
      }
      sqlDynamicUser = this.getFormattedSQL(sqlDynamicUser.toString());
      StringBuffer sqlDynamicUserCnt = getPendingUserProgressCountSql(sqlDynamicUser);
      PreparedStatement preStatDynamicUserCnt = dbConn.prepareStatement(sqlDynamicUserCnt.toString());
      setDynamicPreStatementFilterBy(searchForm, preStatDynamicUserCnt, userRecord.getID(), bFullList, 1);
      ResultSet rsDynamic = preStatDynamicUserCnt.executeQuery();
      int dynamicCount = 0;
      if (rsDynamic.next()) {
        dynamicCount = rsDynamic.getInt(1);
      }
      return dynamicCount;
    }

  private String setDynamicPreStatementFilterBy(AbstractSearchForm searchForm, PreparedStatement preStatCnt, Integer userRecordID, boolean bFullList, int i) throws SQLException {

    // ------------- dynamic assign workflow progress begin -----------
    this.setPrepareStatement(preStatCnt, i++, GlobalConstant.RECORD_STATUS_ACTIVE);
    if (bFullList) {
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_SUBMIT);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_SUBMIT);
    } else {
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_IN_PROGRESS);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_LOCK);
      this.setPrepareStatement(preStatCnt, i++, GlobalConstant.FALSE);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_PENDING);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_IN_PROGRESS);
      this.setPrepareStatement(preStatCnt, i++, WorkflowProgress.STATUS_LOCK);
    }
    //this.setPrepareStatement(preStatCnt, i++, userRecordID.toString());
    // ------------- dynamic assign workflow progress end --------------
    if (searchForm.isSearchable()) {
      String searchKeyword = this.getFormattedKeyword(searchForm.getBasicSearchKeyword(), searchForm.getBasicSearchType());
      this.setPrepareStatement(preStatCnt, i++, searchKeyword);
    }
    String permissionKeyword = this.getFormattedKeyword(WORKFLOW_PERMISSION_TYPE_EXECUTE, "LIKE");
    this.setPrepareStatement(preStatCnt, i++, permissionKeyword);
    return permissionKeyword;
  }
//king---add---end---

/**
 * Gets a list of user record id that is dynamically assigned for this task
 *
 * @param progressID The current workflow progress id
 * @return List of desired user record id
 * @throws ApplicationException
 */
public synchronized List getListUserIDForDynamicAssignProgress(Integer progressID) throws ApplicationException {
  MtmWorkflowDynamicUserActorDAObject dynamicUserActor = new MtmWorkflowDynamicUserActorDAObject(sessionContainer,dbConn);
  List userIDList = dynamicUserActor.getDynamicUserIDListByWorkflowProgressID(progressID);

  if(Utility.isEmpty(userIDList)) {
    return new ArrayList();
  }

  return userIDList;
}

public synchronized String getStageNameByStepID(Integer stepID) throws ApplicationException{
  PreparedStatement preStat = null;
  ResultSet rs = null;
  StringBuffer sqlStat = new StringBuffer();
  if(Utility.isEmpty(stepID)) {
    return null;
  }
  synchronized (dbConn){

  sqlStat.append("SELECT WSTAGE.STAGE_NAME\n");
  sqlStat.append("FROM MTM_WF_STAGE_WF_STEP SS,WORKFLOW_STAGE WSTAGE \n");
  sqlStat.append("WHERE WSTAGE.ID=SS.WORKFLOW_STAGE_ID AND \n");
  sqlStat.append("      SS.WORKFLOW_STEP_ID=?");
  try{
    preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
    this.setPrepareStatement(preStat, 1,stepID);
    rs = preStat.executeQuery();
    if(rs.next()) {
      return getResultSetString(rs, "STAGE_NAME");
    }
  }catch (SQLException sqle) {
    log.error(sqle, sqle);
    throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
  } catch (Exception e) {
    log.error(e, e);
    throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
  } finally {
    try {
      rs.close();
    } catch (Exception ignore) {
    } finally {
      rs = null;
    }
    try {
      preStat.close();
    } catch (Exception ignore) {
    } finally {
      preStat = null;
    }
  }
  }
 return null;
}
/**
 * Check this progress of trackID is complete
 * @param trackID The workflow track ID
 * @return boolean,true is complete,false is not complete
 * @throws ApplicationException
 */
  public synchronized boolean checkProgressComplete(Integer trackID) throws ApplicationException {
  ResultSet rs = null;
  StringBuffer sqlStat = new StringBuffer();
  PreparedStatement preStat = null;
  synchronized (dbConn) {
    try {
      sqlStat.append("SELECT A.ID, A.WORKFLOW_STEP_ID, A.TRACK_ID, A.CANCEL_FLAG, A.COMPLETE_FLAG, A.SEQ_NO, A.STATUS, A.POST_PROGRESS, A.DUE_DATE, A.NEXT_STEP_DUE_DATES, A.PROGRESS_PRIORITY, A.USER_DEF_1, A.USER_DEF_2, A.USER_DEF_3, A.USER_DEF_4, A.USER_DEF_5, A.RECORD_STATUS, A.UPDATE_COUNT, A.CREATOR_ID, A.CREATE_DATE, A.UPDATER_ID, A.UPDATE_DATE ");
      sqlStat.append("FROM   WORKFLOW_PROGRESS A ");
      sqlStat.append("WHERE  A.RECORD_STATUS = ? AND A.TRACK_ID = ? AND A.STATUS <> ? AND ");
      sqlStat.append("A.STATUS <> ? AND A.STATUS <> ? ");
      sqlStat.append("ORDER BY A.SEQ_NO ASC ");
      preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      this.setPrepareStatement(preStat, 1, GlobalConstant.RECORD_STATUS_ACTIVE);
      this.setPrepareStatement(preStat, 2, trackID);
      this.setPrepareStatement(preStat, 3, WorkflowProgress.STATUS_PENDING);
      this.setPrepareStatement(preStat, 4, WorkflowProgress.STATUS_IN_PROGRESS);
      this.setPrepareStatement(preStat, 5, WorkflowProgress.STATUS_LOCK);
      rs = preStat.executeQuery();
      rs.next();
      String completeFlag=rs.getString("COMPLETE_FLAG");
      // when completeFlag is "Y" then this progress of trackID is complete
      // when completeFlag is "N" then this progress of trackID is't complete
      boolean isCompleteFlag=GlobalConstant.TRUE.equals(completeFlag);
      return isCompleteFlag;
    }catch (SQLException sqle) {
      log.error(sqle, sqle);
      throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
    }catch (Exception e) {
      log.error(e, e);
      throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
    } finally {
      try {
        rs.close();
      } catch (Exception ignore) {
      } finally {
        rs = null;
      }
      try {
        preStat.close();
      } catch (Exception ignore) {
      } finally {
        preStat = null;
      }
    }
  }
}
  /**
   * Check this progress of trackID is complete
   * @param userID The current user ID
   * @return userDelegationList
   * @throws ApplicationException
   */
  public synchronized List getUserDelegationList(Integer userID) throws ApplicationException {
    if(Utility.isEmpty(userID)){
      return null;
    }
    ResultSet rs = null;
    StringBuffer sqlStat = new StringBuffer();
    PreparedStatement preStat = null;
    List userDelegationList = new ArrayList();
    UserRecordDAObject userRecordDAO = new UserRecordDAObject(sessionContainer, dbConn);
    Integer userGroupID = userRecordDAO.getUserGroupIDbyUserID(userID);
    Integer userRoleID = userRecordDAO.getUserRoleIDbyUserID(userID);
    synchronized (dbConn) {
      try {
        sqlStat.append(" SELECT DISTINCT A.SOURCE_USER_ID FROM USER_DELEGATION A WHERE A.RECORD_STATUS ='A' ");
        sqlStat.append(" AND((A.TARGET_OBJECT_ID = ? AND A.TARGET_OBJECT_TYPE = 'U') ");
        if(!Utility.isEmpty(userGroupID)){
          sqlStat.append(" OR (A.TARGET_OBJECT_ID = ? AND A.TARGET_OBJECT_TYPE = 'G') ");
        }
        if(!Utility.isEmpty(userRoleID)){
          sqlStat.append(" OR( A.TARGET_OBJECT_ID = ? AND A.TARGET_OBJECT_TYPE = 'R') ");
        }
        sqlStat.append(" ) ");
        preStat = dbConn.prepareStatement(sqlStat.toString(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        int i=1;
        this.setPrepareStatement(preStat, i++, userID);
        if(!Utility.isEmpty(userGroupID)){
          this.setPrepareStatement(preStat, i++, userGroupID);
        }
        if(!Utility.isEmpty(userRoleID)){
            this.setPrepareStatement(preStat, i++, userRoleID);
        }
        rs = preStat.executeQuery();
        while (rs.next()) {
          userDelegationList.add(getResultSetInteger(rs, "SOURCE_USER_ID"));
        }
        return userDelegationList;
      } catch (SQLException sqle) {
        log.error(sqle, sqle);
        throw new ApplicationException(ErrorConstant.DB_GENERAL_ERROR, sqle, sqle.toString());
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR, e);
      } finally {
        DbUtils.closeQuietly(rs);
        DbUtils.closeQuietly(preStat);
      }
    }
  }
}